鱼C论坛

 找回密码
 立即注册
查看: 163|回复: 9

求大佬解释下谢谢

[复制链接]
发表于 2024-10-15 20:20:58 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
#include <sys_head.h>//自定义头文件已包含下列代码中使用的函数所需头文件
int *ptr;
void END(void)
{
    if (NULL != ptr)
    {
        printf("\n");
        for (int i = 0; i < 10; i++)
        {
            printf("%d\t", ptr[i]);
        }

        free(ptr);
        printf("\n内存释放成功\n");
    }
}

int main(int argc, char *argv[])
{
    ptr = (int *)malloc(sizeof(int) * 10);
    if (NULL == ptr)
    {
        ERRLOG("内存分配失败");
        return EOF;
    }
    memset(ptr, 0, sizeof(int) * 10);
    for (int i = 0; i < 10; i++)
    {
        printf("请输入一个整数:");
        scanf("%d", &ptr[i]);
    }
    for (int i = 0; i < 10; i++)
    {
        printf("%d\t", ptr[i]);
    }
    int pid = fork();

    if (pid == 0)
    {
        atexit(END); // 注册退出函数
    }
    else if (pid > 0)
    {
        printf("\n我是父进程我的子进程的pid是%d\n", pid);
    }

    return 0;


屏幕输出内容如下:
请输入一个整数:1
请输入一个整数:2
请输入一个整数:3
请输入一个整数:4
请输入一个整数:5
请输入一个整数:6
请输入一个整数:7
请输入一个整数:8
请输入一个整数:9
请输入一个整数:10
1       2       3       4       5       6       7       8       9       10
我是父进程我的子进程的pid是14838
1       2       3       4       5       6       7       8       9       10
1       2       3       4       5       6       7       8       9       10
内存释放成功



问为什么执行子进程打印了2变数组的内容?





想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-10-15 20:21:05 | 显示全部楼层
你的代码中有几个问题,导致子进程输出不符合预期。下面我对代码中一些关键的地方进行解释:

1. **错误地访问指针数组**:
scanf("%d", &ptr);
   这里应该是 `scanf("%d", &ptr[i]);`,表示将用户输入的整数存储到 `ptr` 指向的数组中。当前代码每次输入都会将值写入指针 `ptr` 的地址,导致未在数组中存储任何值。

2. **错误地打印数组内容**:
for (int i = 0; i < 10; i++) {
       printf("%d\t", ptr);
   }
   应该是 `printf("%d\t", ptr[i]);`,这样才能逐个打印数组元素,而不是重复打印指针地址的值。

3. **子进程的输出**:
   由于子进程直接从父进程的内存空间复制而来,所以执行 `atexit(END);` 之后会在子进程结束时输出一次数组和释放内存信息。这是为什么你看到两个输出的原因,但实际内容并未按照你期望地存储和打印。

因此,当你修正输入和输出的数组索引问题后,代码应该只正确输出一次数组内容,子进程和父进程会分别输出。(每个进程都应用同样的内存,在每次输入时都应该检查和验证内存操作是否如预期执行。)

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-10-15 20:25:55 | 显示全部楼层
FishC 发表于 2024-10-15 20:21
你的代码中有几个问题,导致子进程输出不符合预期。下面我对代码中一些关键的地方进行解释:

1. **错误 ...

你这错误看错了把,我这打印和获取变量都是对的呀
主要让你解释执行子进程为啥会打印2个数组信息,内存释放成功这条文本又只执行一次
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-15 20:26:02 | 显示全部楼层
轻语远歌 发表于 2024-10-15 20:25
你这错误看错了把,我这打印和获取变量都是对的呀
主 ...


非常抱歉刚才的解答没能准确针对你的问题。

解释执行结果:
1. **子进程与父进程的区别**:
   当调用 `fork()` 时,子进程会复制父进程的整个内存空间。因此,子进程里的 `ptr` 和父进程里的 `ptr` 指向的是相同的数据内容,但处于各自进程的内存空间中。

2. **`atexit(END)`的影响**:
   你在子进程中注册了 `END` 函数,意味着子进程结束时会调用 `END`。因此,子进程在结束时会打印一次数组并释放它自己的 `ptr` 指向的内存。

3. **父进程的输出**:
   父进程并没有注册 `atexit(END)`,所以在父进程正常结束时并没有执行 `END`,只会输出子进程创建和相关信息。

4. **内存释放的现象**:
   “内存释放成功”仅输出一次是因为只有子进程调用了 `END` 函数。父进程没有注册这个函数,自然也就不会打印“内存释放成功”。注意,因为父进程终止时操作系统自动回收资源,所以不影响整体资源管理。

综上,由于 `fork()` 复制进程后,两个进程各自有一份独立的 `ptr`,所以在子进程结束时看到两次数组打印信息和一次内存释放信息。通过理解 `fork()` 的复制机制和 `atexit()` 的注册机制,可以清楚地解答这种行为。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-10-15 20:32:41 | 显示全部楼层
FishC 发表于 2024-10-15 20:26
非常抱歉刚才的解答没能准确针对你的问题。

解释执行结果:

还是不太理解数组内容是怎末打印了2次,这2次内容是那个进程打印的,若都是子进程打印那不应该都是打印2次吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-15 20:43:40 | 显示全部楼层
轻语远歌 发表于 2024-10-15 20:32
还是不太理解数组内容是怎末打印了2次,这2次内容是那 ...


非常抱歉之前解释不够清晰。

在你的代码中,对于为什么子进程打印了两次数组内容,可以通过以下细节来解释:

1. **子进程的执行**:
   - `atexit(END);` 注册了 `END` 函数,当子进程结束时,`END` 函数会被调用。
   - 子进程继承了父进程的整个内存空间和文件指针,所以它们都持有 `ptr` 的相同引用。当子进程运行完自己的代码块并在 `return 0;` (或进程正常退出)前,`atexit` 注册的 `END` 函数会被调用。

2. **END 函数被调用的次数**:
   - 由于在子进程中注册并调用了 `END` 函数,导致子进程退出时调用 `END`,从而打印数组内容。
   - 因此,子进程会调用 `END` 一次,并在 `END` 中打印一次数组内容。

3. **内存释放的次数**:
   - 由于 `END` 在子进程中被调用且 `ptr` 只在子进程的地址空间被释放一次,而父进程并没有调用 `END`,因此 "内存释放成功" 只被输出一次。

总结:子进程调用了 `END`,因此输出了数组两次,而"内存释放成功"也是在子进程中执行的,由于没有在父进程注册 `END`,父进程没有额外的输出。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-10-15 20:51:30 | 显示全部楼层
FishC 发表于 2024-10-15 20:43
非常抱歉之前解释不够清晰。

在你的代码中,对于为什么子进程打印了两次数组内容,可以通过以下细节 ...

如果子进程调用了2次END()函数那么内存释放成功不应该要打印2次吗?

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-15 20:51:40 | 显示全部楼层
轻语远歌 发表于 2024-10-15 20:51
如果子进程调用了2次END()函数那么内存释放成功不应该 ...


抱歉之前没有解释清楚。实际上,子进程只调用了一次 `END()` 函数。我们来看过程:

1. **子进程的退出行为**:
   - `atexit(END);` 只会在正常退出时调用 `END()` 函数一次。
   - 子进程和父进程实际上都有各自独立的 `ptr` 副本,但 `free(ptr);` 只应用于调用它的进程(在这里是子进程)。

2. **子进程打印两次数组内容**:
   - `fork()` 产生的子进程会从父进程中完全复制一份,因此最开始时候子进程里此时 `ptr` 的内容与父进程的一样。
   - 第一次打印数组内容是在你已经输入完数据之后立刻显示(直接在 `scanf` 后面的循环),这每次都由子进程和父进程执行。
   - 第二次是当子进程退出时,`atexit` 调用了 `END` 函数来打印数组并释放内存,因此子进程最终把数组内容和内存释放提示打印出来。

总结来说,第一次打印来自于 `main` 中的循环,第二次打印来自于 `END` 函数。子进程的 `END` 函数只调用了一次,所以内存释放的提示信息也只打印一次。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-10-15 20:58:19 | 显示全部楼层
FishC 发表于 2024-10-15 20:51
抱歉之前没有解释清楚。实际上,子进程只调用了一次 `END()` 函数。我们来看过程:

1. **子进程的退 ...

数组的内容一共打印了3次呀,第一次是在子进程没有创建前打印的,在打印我是父进程我的子进程ID是这一行文本下面的一行数组内容是如何打印出来的,fock()创建子进程不是主进程和子进程都是执行fock()以下的代码内容吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-15 21:03:28 | 显示全部楼层
轻语远歌 发表于 2024-10-15 20:58
数组的内容一共打印了3次呀,第一次是在子进程没有创 ...


你说得没错,`fork()` 后,父进程和子进程都会继续执行 `fork()` 之后的代码。

在你的代码中,数组内容打印三次的情况如下:

1. **第一次打印**:在 `fork()` 之前,`main` 函数中的循环打印出数组内容。

2. **第二次打印**:子进程创建后,会从 `fork()` 之后继续执行,因为子进程继承了父进程的内存空间,所以它会打印一次数组内容以及 "我是父进程..." 的信息。

3. **第三次打印**:子进程退出时调用注册在 `atexit` 的 `END` 函数,再次打印数组内容,并释放内存。

对子进程而言,在 `fork()` 之后代码继续执行,并由于 `atexit` 注册的 `END` 函数,导致数组内容和 "内存释放成功" 各打印一次。对于父进程,它只在 `fork()` 之后打印了一次 "我是父进程…" 的信息。

这样的执行顺序确实可以导致在你所看到的程序输出中,数组内容被打印三次,但因具体环境差异,第二次和第三次可能顺序有所不同。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-21 18:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表