【问题标题】:C: Segfault caused by assigning string to struct array using strcpyC:使用 strcpy 将字符串分配给结构数组导致的段错误
【发布时间】:2020-02-02 21:01:35
【问题描述】:

我正在阅读一个包含 10 行和 3 列的文本文件。每个元素都需要放入一个数组中以进行进一步操作。 fileToArray 方法将挑选出每个字符串,我可以成功地单独打印每个字符串,但是我似乎无法正确地将字符串分配给每个索引。

我的理解是我有一个指向 10 个 dataArrays 的指针,在我的 switch 语句中,基本上发生的是 dataArray[0].pName = P1 ... dataArray[1].pName = P2 ... etc... 和结构中的其他变量也是如此。

文本文件最多有 10 行,因此初始化了 10 个数组。

是我的理解有缺陷还是我的代码中有一些明显的错误?

struct Processes
{
    char *pName;
    char *arvTime;
    char *srvTime;
};
void fileToArray(FILE *fp, struct Processes dataArray[])
{
    // temp[14] because 14 is the max size a line can be
    char temp[14];
    char delim[] = " \n";
    int count = 0;
    int a, b, c = 0;

    while(fgets(temp, 14, fp) != NULL)
    {
        char *ptr = strtok(temp, delim);

        while(ptr != NULL)
        {
            // printf("'%s'\n", ptr);
            // ^^^^ This line will successfully print out each string

            switch(count)
            {
            case 0:
                dataArray[a].pName = malloc(strlen(ptr + 1));
                strcpy(dataArray[a].pName, ptr);
                a++;
                count++;
                free(dataArray[a].pName);
                break;

            case 1:
                dataArray[b].arvTime = malloc(strlen(ptr + 1));
                strcpy(dataArray[b].arvTime, ptr);
                b++;
                count++;
                free(dataArray[b].arvTime);
                break;

            case 2:
                dataArray[c].srvTime = malloc(strlen(ptr + 1));
                strcpy(dataArray[c].srvTime, ptr);
                c++;
                count = 0;
                free(dataArray[c].srvTime);
                break;
            }


            ptr = strtok(NULL, delim);

        }
    }
}
int main(int argc, void *argv[])
{
    struct Processes dataArray[10];

    if(argc == 1)
    {
        FILE *fp;

        fp = fopen("process-data.txt", "r");

        fileToArray(fp, dataArray);

        fclose(fp);
    }
    return 0;
}
// Sample text file being read //
P1 1 5
P2 2 2
P3 11 5
P4 17 9
P5 3 1
P6 10 10
P7 4 3
P8 4 1
P9 7 8
P10 5 4

运行此代码会导致段错误,我不确定原因。查看其他类似的帖子,该解决方案似乎没有使用 malloc() 这让我认为我错误地实现了该功能。

【问题讨论】:

  • 这里 dataArray[a].pName = malloc(strlen(ptr + 1));使用了未初始化的变量 a。所以程序已经有未定义的行为。
  • 这不能解决您的问题,但 int main(int argc, void *argv[]) 不是 main 的有效定义——您的选择是 int main(void)int main(int argc char *argv[])/char** argv
  • 为什么你free复制了字符串之后的数据?现在没有分配给它的存储空间了。尝试访问它(您没有显示)将导致 seg 错误。
  • 使用a、b、c三个索引,好像有点没用。您希望每个数组条目都填充三个数据部分。一个索引就足够了。
  • 请注意 int a, b, c = 0; 仅将 c 初始化为 0。ab 未初始化,IOW 它们最初将包含一个不确定的值。你可能想要这个:int a = 0, b = 0, c = 0;

标签: c struct segmentation-fault malloc strcpy


【解决方案1】:

对于初学者,您应该将数组中元素的数量传递给函数。所以函数声明应该是这样的

void fileToArray( struct Processes dataArray[], size_t n, FILE *fp );

而且最好是函数返回数组的填充元素个数。

size_t fileToArray( struct Processes dataArray[], size_t n, FILE *fp );

并且函数至少可以像这样调用

size_t n = fileToArray( dataArray, 10, fp );

在此声明中

int a, b, c = 0;

只有变量c 被初始化。所有其他变量 a 和 b 都未初始化。所以例如这个语句

dataArray[a].pName = malloc(strlen(ptr + 1));

导致未定义的行为。

这个表达式

malloc(strlen(ptr + 1))

无效。相当于

malloc(strlen( &ptr[1] ))

在分配内存后立即释放内存没有任何意义。

free(dataArray[a].pName);

函数可以这样定义

size_t fileToArray( struct Processes dataArray[], size_t n, FILE *fp )
{
    // temp[14] because 14 is the max size a line can be
    char temp[14];
    char delim[] = " \n";

    size_t i = 0;

    for( ; i < n && fgets( temp, sizeof( temp ), fp) != NULL; i++ )
    {
        dataArray[i].pName   = NULL;
        dataArray[i].arvTime = NULL;
        dataArray[i].srvTime = NULL;

        char *ptr = strtok( temp, delim );

        for( size_t j = 0; j < 3 && ptr != NULL; j++ )
        {
            switch ( j )
            {
            case 0:
                dataArray[i].pName = malloc( strlen( ptr ) + 1 );
                strcpy( dataArray[i].pName, ptr );
                break;

            case 1:
                dataArray[i].arvTime = malloc( strlen( ptr ) + 1 );
                strcpy( dataArray[i].arvTime, ptr );
                break;

            case 2:
                dataArray[i].srvTime = malloc( strlen( ptr ) + 1 );
                strcpy( dataArray[i].srvTime, ptr );
                break;
            }

            ptr = strtok( NULL, delim );
        }
    }

    return i;
}

【讨论】:

    【解决方案2】:

    这段代码的作用与你的想法完全相反

    malloc(strlen(ptr + 1))
    

    不是为字符串分配足够的空间,最后为 NUL 分配 1 个额外的空间,而是分配比字符串长度少 1 个的空间。您想像这样将+ 1 移动到strlen 的调用之外

    malloc(strlen(ptr)+1)
    

    您还应该将ab 的值初始化为0 或更好,将abc 组合成一个变量,并且仅在您读到第三个变量时才增加它一条信息。

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 1970-01-01
      • 2021-06-24
      • 2018-07-28
      • 2017-02-25
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多