为什么这个C程序会崩溃?
我已经仔细研究了这个至少一个小时,我仍然无法找出问题所在。
#include typedef struct { int Level; char* Name; } Base; Base baseStruct; int main(int argc, char *argv[]) { scanf("%s", baseStruct.Name); scanf("%d", &baseStruct.Level); printf("%s :: Level %d\n", baseStruct.Name, baseStruct.Level); return 0; }
会发生什么,我去输入“Name”字符串,然后当我输入并输入整数时程序崩溃。 到底是怎么回事?
scanf("%s", ...)
这需要一个缓冲区( scanf
需要写入它),你给它一个未初始化的指针,它可以指向任何地方。
考虑执行以下操作之一:
-
将
Name
为字符缓冲区:typedef struct { int Level; char Name[100]; } Base;
-
从堆初始化它:
baseStruct.Name = malloc(100); /* do not forget to cleanup with `free()` */
您还应该在scanf
格式字符串中指定最大字符串长度以防止溢出:
/* assume 'Name' is a buffer 100 characters long */ scanf("%99s", baseStruct.Name);
不要心疼每个人都会犯这个错误。 char *代表“指向字符的指针”,但不分配字符串本身的内存。
加:
baseStruct.Name = malloc(sizeof(char)* 100);
(注意我的语法可能有些偏差)
Name只是一个指向字符串的未初始化指针。 它没有指出任何有用的东西。 您需要将其正确初始化为字符串缓冲区。 此外,您可能希望通过格式限制字符串(如%100s)以确保不会超出缓冲区。
您尚未为Base.Name分配任何存储空间。 您正在将字符串扫描为不指向任何存储的指针。
为字符串分配一些空间。 问题是你不知道使用scanf复制一个字符串有多大。 假设你malloc 256字节然后scanf加载300字节的字符串? 要么分配足够大的字符串来处理scanf的所有可能结果,要么修改scanf以限制字符,例如:
baseStruct.Name = malloc(sizeof(char) * 256); scanf("%256s", baseStruct.Name);
正如其他人所指出的那样, baseStruct.Name
并不指向有效的内存区域。 但是,分配固定大小的缓冲区并不安全。 对于学习练习,请使用
typedef struct { int Level; char Name[1]; } Base;
并输入长字符串以检查缓冲区溢出的影响。
为了安全处理不确定长度的输入,请使用fgets
和sscanf
或strtol
(如果Base.Level
不能为负,则使用strtoul
。
这是一个例子:
#include #include #include #include #include #define INITIAL_BUFSIZE 100 #define MAX_BUFSIZE 30000 char *myreadline(FILE *fin) { char *buffer; int offset = 0; int bufsize = INITIAL_BUFSIZE; buffer = malloc(bufsize); if ( !buffer ) { return NULL; } while ( fgets(buffer + offset, bufsize, fin) ) { size_t last = strlen(buffer) - 1; if ( buffer[last] == (char) '\n' ) { buffer[last] = 0; break; } else { char *tmp; offset += bufsize - 1; bufsize *= 2; if ( bufsize > MAX_BUFSIZE ) { break; } tmp = realloc(buffer, bufsize); if ( !tmp ) { break; } else { buffer = tmp; } } } return buffer; } int myreadint(FILE *fin, int *i) { long x; char *endp; char *line = myreadline(fin); if ( !line ) { return 0; } x = strtol(line, &endp, 10); if ( (!*endp || isspace((unsigned char) *endp) ) && (x >= INT_MIN) && (x <= INT_MAX ) ) { *i = (int) x; free(line); return 1; } return 0; } typedef struct base_struct { int Level; char* Name; } Base; int main(int argc, char *argv[]) { Base bs; int i; puts("Enter name:"); bs.Name = myreadline(stdin); if ( !bs.Name ) { fputs("Cannot read Name", stderr); return EXIT_FAILURE; } puts("Enter level:"); if ( myreadint(stdin, &i) ) { bs.Level = i; printf("Name: %s\nLevel: %d\n", bs.Name, bs.Level); free(bs.Name); } else { fputs("Cannot read Level", stderr); return EXIT_FAILURE; } return 0; }
输出:
C:\ Temp> t 输入名字: 一个黑暗而神秘的地牢 输入等级: 3456772 名称:一个黑暗神秘的地牢 等级:3456772