我已经仔细考虑过这个问题至少一个小时了,我仍然无法找出问题所在。
#include <stdio.h>
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”字符串,然后当我输入并输入整数时程序崩溃。发生了什么事?
答案 0 :(得分:12)
scanf("%s", ...)
这需要一个缓冲区(scanf
需要将写入它)并且你给它一个未初始化的指针,它可以指向任何地方。
考虑执行以下操作之一:
改为使Name
为字符缓冲区:
typedef struct
{
int Level;
char Name[100];
} Base;
从堆中初始化它:
baseStruct.Name = malloc(100); /* do not forget to cleanup with `free()` */
您还应该以{{1}}格式字符串指定最大字符串长度以防止溢出:
scanf
答案 1 :(得分:1)
Name只是一个指向字符串的未初始化指针。它没有指出任何有用的东西。您需要将其正确初始化为字符串缓冲区。此外,您可能希望通过格式化限制字符串(如%100s),以确保不会超出缓冲区。
答案 2 :(得分:1)
不要心疼每个人都会犯这个错误。 char *代表“指向字符的指针”,但字符串本身的内存未分配。
添加:
baseStruct.Name = malloc(sizeof(char)* 100);
(注意我的语法可能有点偏差)
答案 3 :(得分:0)
您尚未为Base.Name分配任何存储空间。您正在将字符串扫描为不指向任何存储的指针。
为字符串分配一些空间。问题是你不知道使用scanf复制一个字符串有多大。假设你malloc 256字节然后scanf加载300字节的字符串?要么分配足够大的字符串来处理scanf的所有可能结果,要么修改scanf来限制字符,例如:
baseStruct.Name = malloc(sizeof(char) * 256);
scanf("%256s", baseStruct.Name);
答案 4 :(得分:0)
正如其他人所指出的那样,baseStruct.Name
并未指向有效的内存区域。但是,分配固定大小的缓冲区并不安全。对于学习练习,请使用
typedef struct
{
int Level;
char Name[1];
} Base;
并输入长字符串以检查缓冲区溢出的影响。
为了安全处理不确定长度的输入,请使用fgets
和sscanf
或strtol
(或strtoul
如果Base.Level
不能为负数。
以下是一个例子:
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 Enter name: A dark and mysterious dungeon Enter level: 3456772 Name: A dark and mysterious dungeon Level: 3456772