当我放入简单的int变量时崩溃

时间:2013-06-24 17:35:11

标签: c input

我有简单的输入功能:

int main(void)
{
    char *first;
    char *last;

    scanf("%s", first);

    printf("%s", last);

    return 1;
}

但是当我开始扩展我的工作并放置简单的计数器时,程序崩溃了:

int main(void)
{
    int i = 0;
    char *first;
    char *last;

    scanf("%s", first);

    printf("%s", last);

    return 1;
}

任何想法?

4 个答案:

答案 0 :(得分:2)

char *first;

scanf("%s", first);
在致电first之前,

scanf未初始化:呼叫前的值是无效地址。

答案 1 :(得分:1)

您要么在使用char*存储之前动态分配scanf(),要么切换到字符数组。

答案 2 :(得分:1)

问题是first是一个未初始化的指针变量,意味着指针有一个任意值 - 它可能指向内存中的任何位置。

如果你非常幸运,它最终指向未使用的已分配内存,因此读取字符串恰好可以正常工作。

如果你运气好,它最终会指向一个未映射的地址,因此读取一个字符串会导致段错误。

如果你运气不好,它最终会指向一些有效的内存,它会保留其他东西,所以它似乎可以工作,但会覆盖其他数据(或代码),从而导致神秘的难以调试的崩溃,不正确的结果或安全性孔。


添加int i = 0;并没有真正改变任何东西,除了“重新掷骰子”。您也可以通过更改编译器标志来获得不同的结果(特别是如果打开或关闭调试或优化功能)。


例如,当输入main函数时,堆栈的分配区域可能是这样的:

pointer to return address in the middle of libc
pointer to data segment
0

在代码的第一个版本中,您没有初始化任何内容,first最终继承了指向数据段的指针的值,因此扫描到它的工作原理。在第二个版本中,i最终会继承指向数据段的指针(并使用0覆盖它),而first最终会继承0值,因此扫描进入segfaults。


如果您对查看实际情况感兴趣,可以查看由-S标志(或编译器的等效标志)生成的程序集,或者只能printf("%p\n", first)然后查看你得到了什么地址,并弄清楚那里的地图。

但实际上,为什么不起作用并不重要。它不应该工作,唯一的解决方案是正确地将指针初始化为有效的东西(如ouah的回答和其他解释)。

答案 3 :(得分:0)

您的first变量未初始化。将其声明为数组或根据您的需要动态分配。

  1. 数组版本,

    int main(void)
    {
        char first[ SIZE ];     // define SIZE as per your need
        char last[ SIZE ];
    
        scanf("%s", first);
        printf("%s", last);     // FIXME : last is again not initialized
        return 1;
    }
    
  2. 动态版,

    int main(void)
    {
        char *first = malloc( SIZE );     // define SIZE as per your need
        char *last = malloc( SIZE );
    
        scanf("%s", first);
        printf("%s", last);     // FIXME : last is again not initialized
    
        free( first ); first = NULL;
        free( last ); last = NULL;
    
        return 1;
    }