使用scanf()时的Segfault

时间:2016-07-16 12:01:33

标签: c segmentation-fault scanf

我是C的初学者。这是一个简单的程序,提示键盘输入名称,使用名称创建问候语,然后打印它。在运行时,在控制台输入名称并按Enter后立即发生分段故障。调试后我怀疑故障在于scanf()函数。我试过调整这个论点' name'用' *'和'&',并初始化char数组' name'用一个空字符串,但没有一个帮助。

display.blit(pygame.transform.scale(renderLayer,display.get_size()),(0,0))
pygame.display.flip()
clock.tick()
print(clock.get_fps())

4 个答案:

答案 0 :(得分:2)

两次拨打strcat()

char *greeting;
char *suffix;
greeting = "Hello, ";
suffix = ", nice to meet you!";
strcat(greeting, name);
strcat(greeting, suffix);

通过尝试追加属于"字符串" -literal("Hello, ")的存储来激发未定义的行为。

A"字符串" -literal的存储

  1. 常数
  2. 即使它不是,它也不会为任何附加内容提供任何额外的空间。
  3. 要解决此问题,请提供足够大的缓冲区,并在其中复制所需的所有内容:

    char *greeting;
    char *suffix;
    greeting = "Hello, ";
    suffix = ", nice to meet you!";
    char buffer[7 + 20 + 19 + 1]; /* 7 for "Hello, ", 
                                    20 for name (which in fact for your code needed to be 19 only),
                                    19 for ", nice to meet you!" and
                                     1 for the 0-terminator. */
    strcpy(buffer, greeting); /* Use strcpy() to copy to an uninitialised buffer. */ 
    strcat(buffer, name);
    strcat(buffer, suffix);
    

    另外,为了确保用户不会溢出为name提供的内存,请告诉scanf()可用的内容;

      char name[20 + 1]; /* If you need 20 characters, define 1 more to hold the
                            "string"'s 0-terminator. */
    
      scanf("%20s", name); /* Tell scanf() to read in a maximum of 20 chars. */
    

答案 1 :(得分:1)

   strcat(greeting, name);

strcat的此次调用正在修改一个字符串常量 - 这是不合法的,这是导致您的段错误的原因(技术上,您所看到的是未定义行为的结果)。

为了完整性:

scanf("%s", name);

如果缓冲区的大小限制为20,那么您应该使用:

scanf("%19s", name);

...限制实际存储的字符数(尽管有更好的方法来读取可变长度的行)。我使用了19因为nul终结符需要空间。

然后,为您的完整字符串分配合适的存储空间:

char full_greeting[20 + 7 + 19] = ""; // name + "hello"... + "nice to meet"...

复制到那个:

strcpy(full_greeting, greeting);
strcat(full_greeting, name);
strcat(full_greeting, suffix);

printf("%s", full_greeting);

动态字符串解决方案(POSIX)

在POSIX系统上,您可以让scanf为其读取的名称分配缓冲区:

char *name = NULL;
scanf("%ms", &name); // you could also use 'getline' function
if (name == NULL) {
    exit(1); // scanf failed or memory allocation failed
}

(请注意,使用getline会读取整行,这与当前scanf不同,后者读取第一个空格的字符串。

然后,您动态计算缓冲区的长度:

int req_len = strlen(name) + strlen(greeting) + strlen(suffix) + 1;
// (+1 is for nul terminator)
char * buffer = malloc(req_len);
if (buffer == NULL) {
    exit(1); // or handle the error somehow
}
strcpy(buffer, greeting);
strcat(buffer, name);
strcat(buffer, suffix);

printf("%s", buffer);
free(buffer);
free(name);

答案 2 :(得分:1)

问题在于

strcat(greeting, name);

greeting指向read-only内存。将name附加到greeting会尝试更改其中的内容。结果是段错误。

答案 3 :(得分:0)

char *greeting;
char *suffix;
greeting = "Hello, ";
suffix = ", nice to meet you!";
strcat(greeting, name);
strcat(greeting, suffix);

当目的地不仅不可修改,而且太小时,您正在制作strcat。你可能知道写作

char *p = "hello";
*p = 'x';

是未定义的行为。这是strcat对您传入的greeting参数所做的操作。解决方案是

#define MAXBUF 64

char *mystrcat(char *dest, char *src)
{
    while (*dest) 
        dest++;
    while (*dest++ = *src++)
        ;

    return --dest;
}

char greeting[MAXBUF], *p;

strcpy(greeting, "hello, ");
p = mystrcat(greeting, name);
mystrcat(p, ", nice to meet you");

另外,请注意新功能mystrcat。这是Joel Spolsky's famous post中解释的优化。