Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么这个C程序会崩溃?_C - Fatal编程技术网

为什么这个C程序会崩溃?

为什么这个C程序会崩溃?,c,C,我已经考虑了至少一个小时,但我仍然不知道问题出在哪里 #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("%

我已经考虑了至少一个小时,但我仍然不知道问题出在哪里

#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;
}
#包括
类型定义结构
{
智力水平;
字符*名称;
}基础;
基本结构;
int main(int argc,char*argv[])
{
scanf(“%s”,baseStruct.Name);
scanf(“%d”和baseStruct.Level);
printf(“%s::级别%d\n”,baseStruct.Name,baseStruct.Level);
返回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
    (或
    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;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义初始尺寸100
    #定义最大尺寸30000
    char*myreadline(文件*fin){
    字符*缓冲区;
    整数偏移=0;
    int bufsize=初始尺寸;
    缓冲区=malloc(bufsize);
    如果(!缓冲区){
    返回NULL;
    }
    而(fgets(缓冲区+偏移量、bufsize、fin)){
    最后的大小=strlen(缓冲区)-1;
    如果(缓冲区[最后]==(字符)'\n'){
    缓冲区[最后]=0;
    打破
    }
    否则{
    char*tmp;
    偏移量+=bufsize-1;
    bufsize*=2;
    如果(尺寸>最大尺寸){
    打破
    }
    tmp=realloc(缓冲区,bufsize);
    如果(!tmp){
    打破
    }
    否则{
    缓冲区=tmp;
    }
    }
    }
    返回缓冲区;
    }
    int myreadint(文件*fin,int*i){
    长x;
    char*endp;
    char*line=myreadline(fin);
    如果(!行){
    返回0;
    }
    x=strtol(直线和端点,10);
    if((!*endp | | isspace((未签名字符)*endp))
    &&(x>=INT_MIN)和(x t)
    输入名称:
    黑暗而神秘的地牢
    输入级别:
    3456772
    名称:黑暗神秘的地牢
    
    级别:3456772当然,如果用户输入的字符数超过100个,这将严重崩溃。除非您完全确定输入,否则对字符串使用scanf是不安全的。此外,您需要将结果强制转换为char*@EboMike这是C。因此,无需强制转换
    malloc
    @Gabriel
    sizeof(char)的返回值
    总是
    1
    。标准上说
    sizeof(char)
    总是1,所以它不是真的需要。哎哟!您分配了256个字节并指定了
    %256s
    sizeof(char)
    总是1,所以它是多余的。或者,您可以使用
    sizeof(*baseStruct.Name)
    如果
    baseStruct.Name
    的类型可能会从
    char*
    更改为
    wchar\u t*
    ,等等@Kludge:我认为分配足够大的字符串不是一个现实的选择,因为此字符串的大小可能正好是
    malloc
    可以返回的最大大小,而让程序保持sti我很容易受到缓冲区溢出的影响。你在哪里找到C的STL版本?好吧,起诉我,我没有告诉我这是一个C特定的问题。我不认为仅仅使用
    sscanf
    而不是
    scanf
    会有任何区别。如果使用其中任何一个,你仍然必须在格式说明符中输入最大字符串长度。使用
    fgets
    读取输入允许您使用
    realloc
    调整缓冲区大小以适应任何实际大小的字符串。然后您可以使用
    sscanf
    strto(ld)
    转换数字。显然,您在读取字符串时不会使用
    sscanf
    。从
    scanf
    的角度来看,最大字符串长度是可选的,但为了确保您将获得一个工作程序,它应被视为强制性的。不包括最大长度说明符将创建另一个程序易受缓冲区溢出的影响。@Schedler我不确定你的意思。这正是我在回答中说的,不?内存,内存,内存,内存,…&^%(*#分段错误! C:\Temp> t Enter name: A dark and mysterious dungeon Enter level: 3456772 Name: A dark and mysterious dungeon Level: 3456772