【问题标题】:String - Segmentation Fault字符串 - 分段错误
【发布时间】:2012-11-14 17:28:10
【问题描述】:

我对这段代码有疑问。我正在使用 gcc 编译器,当我编译并执行此代码时,我遇到了 seg 错误。我只是分配了两个变量,name_1 作为指针,name_2 作为字符串。当我尝试为这两个值提供字符串输入时,我遇到了段错误。此段错误始终与我正在使用的指针变量相关联。

下面我提供了错误代码和截图。

#include <stdio.h>

int main()
{
char *name_1 ;
char name_2[10] ;

/*      Getting 2 strings as an input from the user
        and is stored in the pointer variable name_1 and name_2*/
scanf("%s",name_1) ;
scanf("%s",name_2) ;

/*      Printing the values of the varibales 
        name_1 and name_2 in string format      */
printf("\n%s",name_1) ;
printf("\n%s",name_2) ;

printf("\n\n") ;
return 0 ;
}

请在这段代码中帮助我。

【问题讨论】:

  • 更改问题以使已经提供的答案无效不是一个好主意。可以留下原件——也许作为评论——并进行更正;仅仅更正代码并使您得到的答案无效是不行的。
  • 请注意,如果您使用 GCC 并使用 -Wall 进行编译,您会收到编译器关于您的错误的警告。如果您使用 GCC,请确保使用(至少)-Wall 进行编译。如果您使用的是其他编译器,请了解如何打开更多警告。
  • 先生,现在我实际上有更多的疑问。每当我声明一个变量时,它不是分配空间吗?
  • name_1 的空间已分配;它是一个char *,因此分配了足够的空间来存储一个char 指针。问题之一是您从未初始化指针以指向某物。问题的另一部分是scanf() 不仅假设指针已初始化,还假设它已初始化,以便它指向一个足够大的内存区域以存储要由scanf() 读取的字符串,包括终止为空。通过将name_1 的定义更改为char name_1[20],您可以确保字符串有20 个字节的空间。
  • [...continued...] 如果您将其更改为:char name_0[20]; char *name_1 = name_0;,那么您已为scanf() 分配空间来存储数据,并初始化name_1 以指向该空间空间。但是,您可以随后改变主意,让name_1 指向不同的区域(例如name_2),如果您愿意的话。哪个最有意义取决于您在读取数据后将如何处理 name_1。

标签: c


【解决方案1】:

char *name_1;,是一个指针。最初,它指向一些随机垃圾。然后,您要求scanf 将一个字符串放置在任何随机垃圾地址name_1 恰好指向您的程序启动时;这是未定义的行为。如果需要,一个符合 C 的 C 实现可以让这个程序只在星期二按预期工作。 :)

如果你要传递一个指针,你必须首先确保它指向一个有效的缓冲区。

此外,您在调用scanf 时存在一定程度的间接违规——name_1 已经是一个指针。您不想将指针传递给指向scanf 的指针;只是一个指针。

【讨论】:

  • 所以。如果 name_1 指针最初指向 NULL 然后在 scanf 中使用,这会起作用吗?
  • @Rajan:不会。scanf 永远不会为您分配缓冲区。这是scanf 在生产代码中使用永远不安全的原因之一;因为分配正确大小的缓冲区是不可能的。
  • 否;如果将char *name_1 = NULL; 传递给scanf(),它将崩溃。
  • @Jonathan:它会崩溃如果你幸运的话——同样,这是未定义的行为,未定义的行为意味着符合标准的实现可以在星期二为你分配一个缓冲区,周三崩溃,其他日子格式化硬盘。 (当然在这种情况下崩溃是最有可能发生的情况:)
  • 你说得对;我过度简化了评论。不;如今,在大多数真实系统上,如果将char *name_1 = NULL; 传递给scanf(),它将崩溃,但行为是未定义的,运行时可以做任何它喜欢的事情,包括让它看起来或多或少地工作。后一种情况很可怕,因为代码不应该工作。但是,如果使用 NULL 指针,您通常会遇到崩溃。
【解决方案2】:

问题的原始版本包含:

char *name_1;
...
scanf("%s", &name_1);

问题已被修改为包含:

char *name_1;
...
scanf("%s", name_1);

您还没有为name_1 分配任何指向的空间。您还将char **(即&amp;name_1)传递给scanf(),格式为%s,预计将获得char *。

可能的修复:

int main(void)
{
    char name_1[20];
    char name_2[10];

    scanf("%s", name_1);
    scanf("%s", name_2);

另一个可能的解决方法:

int main(void)
{
    char name_0[20];
    char *name_1 = name_0;
    char name_2[20];

    scanf("%s", name_1);
    scanf("%s", name_2);

【讨论】:

  • 先生,这样做有什么用?我要指出一个数组是一个更好的主意。但是我为数组变量又浪费了 20 个字节,或者为指针变量浪费了 8 个字节。
  • 您必须设置name_1,使其指向有效的位置以确保您的程序不会崩溃(或者,至少,减少它崩溃的机会——您需要将%s 格式修改为%19s 或 %9s 相当安全)。您必须有空间供scanf() 存储它读取的数据。如果它是一兆字节的空间,你就有理由保持警惕。很少有机器可以使用 8 字节或 20 字节。您不会浪费空间(尽管第二个代码片段肯定会使用更多);你正在使用它。我会选择第一个选项,但这取决于之后如何使用name_1。
【解决方案3】:
char *name_1 ;
...
scanf("%s",&name_1) ;

name_1 是一个悬空指针,您正在尝试使用它,这是不正确的。

【讨论】:

  • 它是一个悬空指针还是只是一个未初始化的指针?悬空指针不是曾经有效但不再有效(指向已退出函数中的局部变量,或指向已被释放的动态分配内存)吗?
  • 我相信在这种情况下更准确的名称是wild pointer,尽管在这种情况下人们似乎确实使用了术语“悬空指针”,尽管它并不完全准确。
【解决方案4】:

你的指针char *name_1 应该指向某个东西。 原则上遵循

Declaring a pointer variable does not create the type of variable, 
it points at. It creates a pointer variable. So in case you are pointing 
to a string buffer you need to specify the character array and a buffer 
pointer and point to the address of the character array.

建议更改:

  • 您可以让char *name_1 指向另一个字符数组或

  • 你可以把它当作一个数组..

【讨论】:

  • 非常感谢先生。我对此感到更加困惑,我现在很好。所以我永远做不到这样。只有分配一个空间,我才能使用代码。?
  • 通过分配空间给数组?我认为您面临的问题是理解指针。我建议你阅读this
  • 谢谢先生。我在使用指针时遇到了麻烦。我通常使用数组而不是指针。
  • 阅读提供链接的 pdf。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多