【问题标题】:How can I make a word as variable in C? [duplicate]如何在 C 中将单词作为变量? [复制]
【发布时间】:2019-08-02 18:32:51
【问题描述】:

我正在尝试学习 C,我正在制作一个非常简单的程序,它会询问你的名字然后显示它。

#include<stdio.h>
main()
{
    char name[30];    
    printf("\n\tWhat is your name?:");    
    scanf("%c",&name);    
    printf("\n\tHi,%c.n\n",name);    
}

在我编译它并尝试输入一个名称后,它只会给出一个随机字母作为printf 的输出。

【问题讨论】:

  • "%c" 是字符的格式说明符。使用"%s"
  • 您在编译代码时是否收到警告消息?它们出于某种原因在那里......不要忽视它们。
  • 成功了,谢谢。我以为“%s”是用于“字符串”的,所以我没有尝试。编译时它没有给出任何警告。
  • 如果你没有从你的编译器中得到任何警告,你需要知道如何让它给你有用的(必要的)警告——或者得到一个更好的编译器。例如,使用 GCC(来自 GNU Compiler Collection 的 GNU C 编译器),您应该使用 gcc -Wall -Wextra -Werror -std=c11 -O3 -g … 或类似的位置进行编译,并且由于 -Werror,您将无法运行代码,直到它编译时没有警告。
  • 是的,“%s”用于字符串,即字符序列。这就是名字。

标签: c arrays string variables


【解决方案1】:

您的代码存在一些问题。让我们看看:

main()
{

你真的应该声明main的返回类型,传统上是int

char name[30];
printf("\n\tWhat is your name?:");    

这里没有真正的问题,只是您正在为经典的缓冲区溢出设置自己。如果有人在您的程序中键入超过 30 个字符,您的程序将在不应该写入的地方写入数据。这是一个典型的安全错误。在这个玩具应用中没什么大不了的,但重要的是要了解

scanf("%c",&name);    

您在此处使用%c 作为格式说明符。这可能是有道理的,因为数据类型看起来像char,但实际上它是char[],即一个字符数组。请改用$s 来收集整个字符串。另外,&amp; 之前确实不需要&amp;...name 包含数组的起始地址,&amp;name 表示相同的意思。

printf("\n\tHi,%c.n\n",name);    

同样的问题:再次使用%s

这是一个可行的版本:

int main(void)
{
    char name[30];
    printf("\n\tWhat is your name?:");
    scanf("%s",name);
    printf("\n\tHi,%s\n",name);
}

【讨论】:

    【解决方案2】:

    这里

    char name[30];
    

    name30 字符的字符缓冲区,即您最多可以存储29 字符作为用户名,1 字节需要为\0 字符保留。 还有这里

    scanf("%c",&name); /* %c is for scanning single character */   
    

    因为name 是字符数组,并且在运行时扫描字符缓冲区使用%s 格式说明符。例如

    scanf("%s", name);  
    

    并且在打印 name 时使用 %s 而不是 %c。例如

    printf("\n\tHi,%s.n\n",name);     
    

    旁注,始终使用最少的警告标志(如-Wall)进行编译。例如

    gcc -Wall -Wextra -pedantic -Werror test.c
    

    您的main() 版本也不如标准所说的那样正确

    5.1.2.2.1 程序启动 定义返回类型int无参数

    int main(void) { /*...*/ }
    

    或带有两个参数(此处称为 argc 和 argv,尽管任何 可以使用名称,因为它们对于它们所在的函数是本地的 声明):

    int main(int argc, char *argv[]) { /*...*/ }
    

    例如

    int main(void) /* No argument i.e void */
    {
        char name[30] = {}; /* initialize the char buffer */
        printf("\n\tWhat is your name?:");
        scanf("%s",name);
        printf("\n\tHi,%s\n",name);
        return 0; /* Add this */
    }
    

    【讨论】:

      【解决方案3】:

      使用clang 编译器,收到以下警告消息:

      prg.c:2:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
      main()
      ^
      prg.c:6:12: warning: format specifies type 'char *' but the argument has type 'char (*)[30]' [-Wformat]
      scanf("%c",&name);    
             ~~  ^~~~~
      prg.c:7:24: warning: format specifies type 'int' but the argument has type 'char *' [-Wformat]
      printf("\n\tHi,%c.n\n",name);    
                     ~~      ^~~~
                     %s
      

      第一个警告是缺少main() 类型说明符。在旧版本的 C (C89/90) 中,如果缺少类型说明符,则默认设置为 int。当然,使用C99 &amp; C11 编译器编译时会收到警告消息,因为不再支持此隐式声明。

      第二条警告消息是针对%c 格式说明符的不兼容参数。如果你想输入一个字符串,你应该使用格式说明符%s。但请记住,%s 格式说明符匹配一系列非空白字符。如果使用宽度说明符,则匹配宽度或直到第一个空白字符,以先出现者为准。所以,如果你输入为

      name surname
      

      它只会消耗name,因为输入中的单词name 后面有空格字符。其余输入将保留在输入缓冲区中。

      您应该使用fgets(),而不是使用scanf(),如下所示:

      if (fgets(name, NAME_LEN, stdin) == NULL) {
          fprintf (stderr, "Input error");
          return -1;
      }
      name[strcspn(name, "\n")] = 0; // to remove trailing \n from input buffer
      

      阅读更多关于fgets()here的信息。

      第三个警告是在printf() 中使用不兼容的格式说明符及其对应的参数。如果你想打印一个字符串,你应该使用%s格式说明符。

      把这些放在一起,你可以这样做:

      #include <stdio.h>
      #include <string.h>
      
      #define NAME_LEN 30
      
      int main(void)
      {
          char name[NAME_LEN];    
          printf("\n\tWhat is your name? : ");    
          if (fgets(name, NAME_LEN, stdin) == NULL) {
              fprintf (stderr, "Input error");
              return -1;
          }
          name[strcspn(name, "\n")] = 0; // to remove trailing \n from input buffer
      
          printf("\n\tHi, %s\n",name);
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        改变这个:

        scanf("%c", &name);    
        

        到这里:

        scanf("%s", name);    
        

        因为name 是一个字符数组,也就是一个字符串,我们使用%s 格式说明符。这就是为什么我们将整个数组作为方法的第二个参数传递,因此我们不再使用&amp;

        %c 用于我们只想使用一个字符时。

        同样,您也应该使用字符串格式说明符进行打印,如下所示:

        printf("\n\tHi,%s.n\n", name);    
        

        我不知道您是否希望将“.n”包含在输出中,但您似乎已经知道如何使用换行符...


        调试提示

        您可以通过在编译器中启用警告标志来轻松解决这个问题。例如,在 GCC 中,我是这样编译的:

        gcc prog.c -Wall -Wextra

        得到:

        prog.c:2:1: warning: return type defaults to 'int' [-Wimplicit-int]
            2 | main()
              | ^~~~
        prog.c: In function 'main':
        prog.c:6:9: warning: format '%c' expects argument of type 'char *', but argument 2 has type 'char (*)[30]' [-Wformat=]
            6 | scanf("%c",&name);
              |        ~^  ~~~~~
              |         |  |
              |         |  char (*)[30]
              |         char *
        prog.c:7:17: warning: format '%c' expects argument of type 'int', but argument 2 has type 'char *' [-Wformat=]
            7 | printf("\n\tHi,%c.n\n",name);
              |                ~^      ~~~~
              |                 |      |
              |                 int    char *
              |                %s
        

        第一个警告可以通过将 main 方法声明为 int main(void) 来消除,第二个和第三个如我们之前讨论的(通过使用 %s)。

        Live demo

        【讨论】:

          猜你喜欢
          • 2014-02-16
          • 2013-07-29
          • 2011-08-06
          • 1970-01-01
          • 2020-01-29
          • 2021-04-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多