[英]Why does this C program crash?
我已經仔細研究了這個至少一個小時,我仍然無法找出問題所在。
#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”字符串,然后當我輸入並輸入整數時程序崩潰。 到底是怎么回事?
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);
Name只是一個指向字符串的未初始化指針。 它沒有指出任何有用的東西。 您需要將其正確初始化為字符串緩沖區。 此外,您可能希望通過格式化限制字符串(如%100s)以確保不會超出緩沖區。
不要心疼每個人都會犯這個錯誤。 char *代表“指向字符的指針”,但不分配字符串本身的內存。
加:
baseStruct.Name = malloc(sizeof(char)* 100);
(注意我的語法可能有點偏差)
您尚未為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 <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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.