c - 二维字符串数组中第一个元素的值在 fork 后意外更改

标签 c arrays string fork

我正在编写一个处理管道的 shell。我得到用户输入并根据输入的管道(如果有的话)将其分成几段并将其放入数组中。数组中的第一项是数组中存储为字符串的元素数。 fork 后,数组中的第一个元素在父进程和子进程中都显示为零或空值。

代码

char *getInput(void)
{
    int bufferSize = 1024;
    char *buffer = malloc(sizeof(char) * bufferSize);
    int counter = 0;
    int c = getchar();

    // Loop through each character in input
    while (c != EOF && c != '\n')
    {
        // Ensure that the buffer can fit the next char
        if (counter <= bufferSize) // If buffer not full
        {
            buffer[counter] = c; // Add character to buffer
        }
        else // If buffer full
        {
            bufferSize = bufferSize + 1024; // Increase buffer size
            buffer[counter] = c; // Add character to buffer
        }

        c = getchar(); // Get the next char
        counter++;
    }

    // Add null to end of buffer
    if (counter <= bufferSize) // If buffer not full
    {
        buffer[counter] = '\0'; // Add null character to end of buffer
    }
    else // If buffer full
    {
        bufferSize = bufferSize + 1024; // Calculate new buffer size
        buffer = realloc(buffer, bufferSize); // Increase buffer size
        buffer[counter] = '\0'; // Add null character to end of buffer
    }

    return buffer;
}

char **split(char *input, char *delimiter)
{
    int counter = 0;
    int bufferSize = 1024;
    //char d[2] = delimiter; // Delimit string by spaces
    char *item = strtok(input, delimiter); // Gets first delimited item
    // Array of items, allocate extra slot to store array size
    char **itemArray = malloc((sizeof(char) * bufferSize) + 1); 

    while (item != NULL) // While items left in string
    {
        itemArray[counter+1] = item; // Insert into array of items
        item = strtok(NULL, delimiter); // Get next delimited item
        counter++;

        if (counter <= bufferSize) // If buffer not full
        {
            bufferSize = bufferSize + 1024; // Calculate new buffer size
            itemArray = realloc(itemArray, bufferSize); // Increase buffer size
        }
    }

    // Store size of array in first array slot
    char size = counter + 48;
    char *sizeP = &size;
    itemArray[0] = sizeP;

    return itemArray;
}

int main(int argc, char *argv[]) 
{
    int loop = 1;
    char *input;
    char **segs;

    // Loop until the EOF command is used
    while (loop)
    {
        input = getInput(); // Get input line
        char *delimiter = "|";
        segs = split(input, delimiter); // Parse for pipe segments or single segment
        if (segs[1] == NULL) return 0; // EOF

        char *segsSizeChar1 = segs[0];
        int numSegs1 = *segsSizeChar1 - '0';
        printf("\nBefore Fork:\n");
        printf("Arr[0]: %i\n", numSegs1);
        printf("Arr[1]: %s\n", segs[1]);

        // Initial Fork
        pid_t pid;
        pid = fork();

        if (pid > 0) // Parent
        {
            char *segsSizeChar2 = segs[0];
            int numSegs2 = *segsSizeChar2 - '0';
            printf("\nIn Parent:\n");
            printf("Arr[0]: %i\n", numSegs2);
            printf("Arr[1]: %s\n", segs[1]);
        }
        else if (pid == 0) // Child
        {
            char *segsSizeChar3 = segs[0];
            int numSegs3 = *segsSizeChar3 - '0';
            printf("\nIn Child:\n");
            printf("Arr[0]: %i\n", numSegs3);
            printf("Arr[1]: %s\n", segs[1]);
        }
        else
        {
            // Catch error
        }
    }
}

输入

ls

输出

Before Fork:                                                                                               
Arr[0]: 1                                                                                                  
Arr[1]: ls                                                                                                 

In Parent:                                                                                                 
Arr[0]: -48                                                                                                
Arr[1]: ls                                                                                                 

In Child:                                                                                                  
Arr[0]: -48                                                                                                
Arr[1]: ls

正如您在父项和子项中看到的那样,arr[0] 具有零值或空值而不是 1(它应该只有一个,因为只有一个段,没有管道)。 奇怪的是,数组的其余部分似乎没问题,因为选择下一个数组元素会显示正确的值。

这个问题似乎是在我 fork 之后直接发生的,但我不确定为什么。

最佳答案

问题是由以下几行引起的:

// Store size of array in first array slot
char size = counter + 48;
char *sizeP = &size;
itemArray[0] = sizeP;

您正在从 split 返回局部变量 size 的地址,并且正在取消引用地址:

  char *segsSizeChar1 = segs[0];
  int numSegs1 = *segsSizeChar1 - '0';

  char *segsSizeChar2 = segs[0];
  int numSegs2 = *segsSizeChar2 - '0';

  char *segsSizeChar3 = segs[0];
  int numSegs3 = *segsSizeChar3 - '0';

这是未定义行为的原因。

您可以通过将 split 中的那些行更改为:

来解决此问题
char *sizeP = malloc(1);
*sizeP = counter + 48;
itemArray[0] = sizeP;

关于c - 二维字符串数组中第一个元素的值在 fork 后意外更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28512858/

相关文章:

C - 奇怪的语法错误

C 段错误 :11

javascript - For循环条件问题

javascript - 组合不同的方法来计算嵌套列表中的元素

c - 是否可以使用 C 中的单个消息队列进行双向通信

c - 给定一个矩阵和一些规则,设置二进制矩阵的所有位所需的最少天数是多少

C++ 无法填充 C 数组的映射

sql - 如何使用 GROUP BY 连接 MySQL 中的字符串?

c++ - 为什么 std::string 在添加整数时返回字符串的尾部

java - Jython 随机字符串生成