轻语远歌 发表于 2024-10-15 20:20:58

求大佬解释下谢谢

#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);
      }

      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);
    }
    for (int i = 0; i < 10; i++)
    {
      printf("%d\t", ptr);
    }
    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变数组的内容?





FishC 发表于 2024-10-15 20:21:05

你的代码中有几个问题,导致子进程输出不符合预期。下面我对代码中一些关键的地方进行解释:

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

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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

轻语远歌 发表于 2024-10-15 20:25:55

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

1. **错误 ...

你这错误看错了把,我这打印和获取变量都是对的呀
主要让你解释执行子进程为啥会打印2个数组信息,内存释放成功这条文本又只执行一次

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

轻语远歌 发表于 2024-10-15 20:32:41

FishC 发表于 2024-10-15 20:26
非常抱歉刚才的解答没能准确针对你的问题。

解释执行结果:


还是不太理解数组内容是怎末打印了2次,这2次内容是那个进程打印的,若都是子进程打印那不应该都是打印2次吗

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

轻语远歌 发表于 2024-10-15 20:51:30

FishC 发表于 2024-10-15 20:43
非常抱歉之前解释不够清晰。

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

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

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

轻语远歌 发表于 2024-10-15 20:58:19

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

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

数组的内容一共打印了3次呀,第一次是在子进程没有创建前打印的,在打印我是父进程我的子进程ID是这一行文本下面的一行数组内容是如何打印出来的,fock()创建子进程不是主进程和子进程都是执行fock()以下的代码内容吗?

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 求大佬解释下谢谢