了解C中的scanf

时间:2013-07-06 06:32:03

标签: c scanf

所以我对编程很新,大约3天前我开始使用C语言。 我正在创建这个简短的程序来测试自己。这只是一个非常基本的C程序,要求你的名字和姓氏。这是代码:

#include <stdio.h>

int main() 
{

    char first[20];

    char last[20];

    printf("Please enter your first name:");
    scanf("%s",&first);
    printf("\nand Please enter your last name:");
    scanf("%s",&last);
    printf("Greetings fellow %s %s!\n",first,last);
    return(0);
}

但是当我去编译时,我每次都会得到这个错误:

checkname.c:9: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’ checkname.c:11: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’

我知道我可以使用gets(),但显然它很糟糕,我不应该使用它。这段代码有什么问题?我不明白问题是什么。

5 个答案:

答案 0 :(得分:7)

  

我知道我可以使用gets(),但显然它很糟糕,我不应该使用它。

确实,确切地说 - 它容易出现缓冲区溢出错误。并且scanf()同样是邪恶的(部分是出于同样的原因 - 指定缓冲区长度并不容易,而且无论如何,它都比必要的更复杂,很难做到正确,而且对于简单的原始I来说它是多么昂贵/ O),也不要使用它。使用fgets()来获取用户输入,通过让你传递要写入的缓冲区的长度,它可以避免被击中:

char buf[0x40];
fgets(buf, sizeof(buf), stdin);

既然您知道“如何”,我会向您解释“为什么”。

当传递给函数时,数组被称为衰减成指针。如果你将char []传递给函数,它会看到char *指向到数组的第一个元素。这就是为什么你不必为(char)数组(概念上是C中的字符串)显式使用“addressof”(&)运算符。

如果你使用它,你不会得到指向数组的第一个元素的指针,而是指向指向数组本身的指针,那不是你的意思想。

(一般情况下,它可以工作,因为它显然适合你,但理论上它会调用undefined behavior,因为传入的表达式的实际类型和%s转换说明符所期望的类型不匹配。)

This document是关于数组和指针的好读物,请务必阅读并理解它。

答案 1 :(得分:2)

您正在使用数组。在输入数组

时,不要将&scanf一起使用

例如:scanf("%s",first);

数组已经通过引用传递。您不需要放置&,因为数组已作为指向C

中第一个元素的指针传递

答案 2 :(得分:1)

尝试将scanf("%s",&first);更改为scanf("%s",first);last的相似度)。

在正常情况下(包括这些),数组的名称将计算为数组中第一个元素的地址。在这种情况下,这是一个指向char的指针,它是scanf转换所需的%s类型。

在开头的&,您获得相同的指针(即,相同的地址),但作为指向数组的指针而不是指向元素的指针数组。由于这与%s所期望的类型不匹配,结果是未定义的行为(尽管它是正确的地址,这通常适用于大多数典型的编译器/ CPU)。

答案 3 :(得分:1)

删除&amp;来自scanf陈述。

scanf("%s", first);  // first is pointer to start of first
scanf("%s", last);   // last is pointer to start of last 

在C中,数组 的名称是指向数组开头的指针

格式参数scanf需要指针参数或参数。

scanf(  "%s", first  );
scanf format-arg input-args

例如,如果整数参数用于scanf,则&amp; (需要地址)运营商是必需的。

int n;
scanf("%d", &n);    // &n is pointer to n

答案 4 :(得分:0)

scanf需要一个地址,但是char数组[]已经是一个地址,而scanf不需要参考符号&amp;因为名称本身就是一个地址