簡體   English   中英

為什么這個C程序會崩潰?

[英]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需要寫入它),你給它一個未初始化的指針,可能指向任何地方。

考慮執行以下操作之一:

  1. Name為字符緩沖區:

     typedef struct { int Level; char Name[100]; } Base; 
  2. 從堆初始化它:

     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;

並輸入長字符串以檢查緩沖區溢出的影響。

為了安全處理不確定長度的輸入,請使用fgetssscanfstrtol (如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM