fgets设置为char*会导致分段错误,动态字符串

fgets设置为char*会导致分段错误,动态字符串,c,pointers,segmentation-fault,scanf,gets,C,Pointers,Segmentation Fault,Scanf,Gets,我正在用c编写一个程序,它查看一个标准输入的文本文件,其中包含行string int。最初,我的程序在scanf中运行良好,但现在名称必须是运行时已知的动态stringsize,当我将grade_条目中的名称切换为指针时,它开始出现分段错误 typedef struct grade_entry { char *name; int grade; } grade_entry; struct grade_entry grade_list[100]; int main()

我正在用c编写一个程序,它查看一个标准输入的文本文件,其中包含行string int。最初,我的程序在scanf中运行良好,但现在名称必须是运行时已知的动态stringsize,当我将grade_条目中的名称切换为指针时,它开始出现分段错误

typedef struct grade_entry {
       char *name;
       int grade;
} grade_entry;

struct grade_entry grade_list[100];

int main(){
    int grade;
    int done;
    int i=0;
    do{
            puts("not weee\n");
            done=(int)strlen(gets(grade_list[i].name));
            puts("weee\n");
    }while(1);
}
编译,当前输出为:

not weee

segmentation fault(core dumped)
**决议: 我分配了指针,然后为size+1重新分配,将null添加到
结束。不幸的是,我不能基于scanf,fgets,get的临时内存立即进行malloc。哦,好的,谢谢大家的帮助

您必须将内存分配给grade_entry.name,否则它是指向任意内存位置的字符指针,写入它会导致分段错误。

您必须将内存分配给grade_entry.name,否则,它是一个指向任意内存位置的char指针,写入它会导致分段错误。

您没有为char*name字段分配内存,但正在该内存中存储值,而您实际上并不拥有这些值

同时,您正在运行一个无限循环,并使用相同的数组元素,而不是增加“i”

下面是我想可以工作的代码

typedef struct grade_entry {
   char *name;
   int grade;
} grade_entry;

int main(){
int grade;
int done;
char str[100];
grade_entry grade_list[10];
int i=0;    
do{
        puts("not weee\n");
        gets(str);
        grade_list[i].name=(char*)malloc(strlen(str));
        done=strlen(grade_list[i++].name);
        puts("weee\n");
  }while(i<10);
}

您尚未为char*name字段分配内存,但正在该内存中存储值,而实际上您并不拥有这些值

同时,您正在运行一个无限循环,并使用相同的数组元素,而不是增加“i”

下面是我想可以工作的代码

typedef struct grade_entry {
   char *name;
   int grade;
} grade_entry;

int main(){
int grade;
int done;
char str[100];
grade_entry grade_list[10];
int i=0;    
do{
        puts("not weee\n");
        gets(str);
        grade_list[i].name=(char*)malloc(strlen(str));
        done=strlen(grade_list[i++].name);
        puts("weee\n");
  }while(i<10);
}
问题在于:

        done=(int)strlen(gets(grade_list[i].name));//Storing in a unallocated memory using an uninitialized pointer. BAD!
此外,在您的代码中,我没有看到您递增/递减/更改I的值,因此基本上您将覆盖grade_列表[0]。每次循环执行时命名。那也很糟糕。内存泄漏太多

这是一个无限循环,没有中断条件

试着这样做:

char buffer[MAX_LENGTH_OF_A_STRING];
memset(buffer,0x00,MAX_LENGTH_OF_A_STRING);
do{
        puts("not weee\n");
        done=strlen(gets(buffer));//This is enough
        grade_list[i].name=malloc(strlen(buffer)+1);
        strncpy(grade_list[i].name,buffer,strlen(buffer)+1);
        memset(buffer,0x00,MAX_LENGTH_OF_A_STRING);
        i++;//You were not doing this
        puts("weee\n");
        //Put some condition to break this infinite loop, somewhere within the loop
}while(1);
问题在于:

        done=(int)strlen(gets(grade_list[i].name));//Storing in a unallocated memory using an uninitialized pointer. BAD!
此外,在您的代码中,我没有看到您递增/递减/更改I的值,因此基本上您将覆盖grade_列表[0]。每次循环执行时命名。那也很糟糕。内存泄漏太多

这是一个无限循环,没有中断条件

试着这样做:

char buffer[MAX_LENGTH_OF_A_STRING];
memset(buffer,0x00,MAX_LENGTH_OF_A_STRING);
do{
        puts("not weee\n");
        done=strlen(gets(buffer));//This is enough
        grade_list[i].name=malloc(strlen(buffer)+1);
        strncpy(grade_list[i].name,buffer,strlen(buffer)+1);
        memset(buffer,0x00,MAX_LENGTH_OF_A_STRING);
        i++;//You were not doing this
        puts("weee\n");
        //Put some condition to break this infinite loop, somewhere within the loop
}while(1);
你不应该使用get-ever。假装它不存在。如果你使用它,假装它会炸毁你的电脑。假设它将被用来使你的程序崩溃——因为它会

问题是,您无法判断它必须使用多少空间

改用fgets。如果您担心读取的行太长,那么您应该希望您的系统具有POSIX 2008功能,它可以为您处理任意长度的读取行。您只需要处理字符指针数组,这更简单

在程序中,指针最终将被复制到数据结构中的指针

这一切都很有趣;关键的是要记住,如果你没有初始化指针,它会随机指向你,在你知道指针指向什么之前,你不能安全地使用它。因此,将指针初始化为指向某处,或初始化为NULL以指示它们不指向任何地方。永远不要取消对空指针的引用。

您不应该使用get-ever。假装它不存在。如果你使用它,假装它会炸毁你的电脑。假设它将被用来使你的程序崩溃——因为它会

问题是,您无法判断它必须使用多少空间

改用fgets。如果您担心读取的行太长,那么您应该希望您的系统具有POSIX 2008功能,它可以为您处理任意长度的读取行。您只需要处理字符指针数组,这更简单

在程序中,指针最终将被复制到数据结构中的指针


这一切都很有趣;关键的是要记住,如果你没有初始化指针,它会随机指向你,在你知道指针指向什么之前,你不能安全地使用它。因此,将指针初始化为指向某处,或初始化为NULL以指示它们不指向任何地方。永远不要取消对空指针的引用。

我打赌您没有为grade_list[I].name.Your问题标题引用函数fgets,但您的代码只引用函数fgets。无论如何,您尚未为char*name字段分配内存,但正在该内存中存储您不拥有的值。是的,数组grade_列表未声明,并且没有为该数组中每个元素中的每个名称分配内存。grade-list在那里,并且Ot在scanf获取和FGET时启动。这是gets尝试的结果。抱歉造成混淆我打赌您没有为grade_list[i].name分配内存。您的问题标题引用函数fgets,但您的代码仅引用函数fgets。无论如何,您尚未为char*name字段分配内存,但正在存储

您不拥有此内存中的值。是的,数组grade_列表未声明,并且没有为该数组中每个元素中的每个名称分配内存。grade-list在那里,并且Ot以scanf获取和FGET开始。这是gets尝试的结果。抱歉弄糊涂了如果我把它全煮了,它会有一个固定的尺寸,对吗?我需要字符串来匹配输入size@Cman131这就是当你使用一种过时的编程语言时会发生的事情。分配一个固定大小的临时缓冲区,其大小足以容纳您期望的名称是的,这会对其大小设置任意限制,使用fgets读取的大小不超过该缓冲区的大小,然后使用strlen分配内存以查找名称的长度别忘了为NUL包含空间。或者编写一个动态分配足够空间来容纳任何大小的行的函数,或者查找具有此函数的现有库中的一个。如果我对其进行allcocate,它将具有设置的大小,对吗?我需要字符串来匹配输入size@Cman131这就是当你使用一种过时的编程语言时会发生的事情。分配一个固定大小的临时缓冲区,其大小足以容纳您期望的名称是的,这会对其大小设置任意限制,使用fgets读取的大小不超过该缓冲区的大小,然后使用strlen分配内存以查找名称的长度别忘了为NUL包含空间。或者编写一个动态分配足够空间来容纳任意大小的行的函数,或者查找具有此函数的现有库之一;您还必须为strlen不计算的尾随“\0”分配空间。strncpy可以防止溢出,但不会以null终止字符串。您的memset操作是不必要的。您不认为在执行malloc时需要将typecast转换为char*吗?我还没来得及发布答案,我的互联网就瘫痪了无论如何,这是我最新的完整答案。@VallabhPatade:关于决定malloc结果的优劣意见分歧。如果是C++,就不会有争论了;演员阵容是强制性的。如果您使用符合C99的选项进行编译,以便在使用函数之前必须声明或定义它们,那么强制转换几乎没有什么危害。如果为C89或预标准C编译,则转换可能会隐藏问题,因为malloc未声明,并被推断为返回int。我在强制转换的系统上学习了C:char*地址使用了其他指针没有使用的地址位。请注意,mallocstrlenbuffer是一个问题;您还必须为strlen不计算的尾随“\0”分配空间。strncpy可以防止溢出,但不会以null终止字符串。您的memset操作是不必要的。您不认为在执行malloc时需要将typecast转换为char*吗?我还没来得及发布答案,我的互联网就瘫痪了无论如何,这是我最新的完整答案。@VallabhPatade:关于决定malloc结果的优劣意见分歧。如果是C++,就不会有争论了;演员阵容是强制性的。如果您使用符合C99的选项进行编译,以便在使用函数之前必须声明或定义它们,那么强制转换几乎没有什么危害。如果为C89或预标准C编译,则转换可能会隐藏问题,因为malloc未声明,并被推断为返回int。我在强制转换的系统上学习了C:char*地址使用了其他指针没有使用的地址位。内存分配短1字节;它应该是mallocstrlenstr+1。也不清楚您是否将字符串复制到分配的空间中-可能是因为您没有分配足够的空间,但这有点浪费精力,而且以后可能会导致意外。是的,我需要执行Mallocstrlenst+1,并且也应该复制字符串。谢谢Jonathan指出这一点。您的内存分配短了1字节;它应该是mallocstrlenstr+1。也不清楚您是否将字符串复制到分配的空间中-可能是因为您没有分配足够的空间,但这有点浪费精力,而且以后可能会导致意外。是的,我需要执行Mallocstrlenst+1,并且也应该复制字符串。谢谢乔纳森指出这一点。