【问题标题】:Why is putting an '&' before a giving me the result I want?为什么在给我想要的结果之前放一个“&”?
【发布时间】:2020-11-10 15:33:22
【问题描述】:

我刚刚开始使用 C,并不真正了解一些事情是如何工作的。我想制作一个程序,它输入一个字符串并按原样打印它。 这是我写的程序:-

#include <stdio.h>
int main()
{
    char a;
    scanf("%s",&a);
    printf("%s",a);
}

我的第一个问题是没有任何输出。甚至不是我期望得到的第一个字符。 其次,当我在 print 语句变量之前放一个 '&' 时,它工作得很好,即打印整个字符串。

#include <stdio.h>
int main()
{
    char a;
    scanf("%s",&a);
    printf("%s",&a);
}

为什么会这样?

【问题讨论】:

    标签: c string printing


    【解决方案1】:

    几件事:

    1. char 类型存储单个字符,而不是字符串。要存储一个字符串,你需要留出一个char:
      char a[20]; // stores a string up to 19 characters long
      array
    2. 在 C 中,字符串 是一个包含 0 值 终止符 的字符值序列。字符串存储在字符类型的数组中。由于该终止符,您需要一个 至少 N+1 个元素宽的数组,以便存储 N 个字符长的字符串。
    3. printfscanf%s 转换说明符期望其对应参数的类型为char *,而不是char - 它期望第一个元素的地址 char数组
    4. 除非它是sizeof 或一元&amp; 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则为“N 元素”类型的表达式 T" 的数组将被转换 ("decay") 为类型为 "pointer to T" 的表达式,表达式的值将是第一个元素的地址。

    将所有这些放在一起,您需要进行以下更改:

    #include <stdio.h>
    
    #define LENGTH 20
    #define EXPAND(x) #x            // I'll explain this in more detail below
    #define STR(x) EXPAND(x)
    #define LENGTH_FMT STR(LENGTH)
    
    int main( void )
    {
      char a[LENGTH+1];
      scanf( "%" LENGTH_FMT "s", a );
      printf( "%s\n", a );
      return 0;
    }
    

    %s 转换说明符本身不知道目标数组有多大,如果您输入的数据多于数组大小可以容纳的数据,它会写到它的末尾。您可以传递一个可选的字段宽度,告诉scanf 将不超过这么多的字符读入数组,但与printf 不同的是,您不能将其作为参数传递 - 您必须将其作为格式的一部分进行硬编码.

    由于我们使用预处理器宏来定义数组的大小,因此我们使用了一些额外的预处理器魔法来将该大小添加到格式说明符中。由于预处理器的工作方式,这是一个多步骤的过程,但它基本上是这样的:

    "%" LENGTH_FMT "s"
    

    扩展到

    "%" STR(LENGTH) "%s"
    

    扩展为

    "%" EXPAND(20) "%s"
    

    扩展为

    "%" #20 "s"
    

    扩展为

    "%" "20" "s"
    

    最终连接成

    "%20s"
    

    所以我们称scanf

    scanf( "%20s", a );
    

    【讨论】:

      【解决方案2】:

      你是我的第二个例子,似乎可以工作,但实际上你正在调用未定义的行为,所以任何事情都可能发生。

      详细说明:

      1. 你有一个char a,你打电话给scanf("%s",&amp;a);但是这里 scanf() 会将整个 NUL 终止的字符串复制到您传递的地址中,因此即使您只键入一个字符,scanf 也会将该字符复制到 a 中,并将 '\0' 复制到 &amp;a + 1 中,这会调用未定义的行为,因此您的程序可能会崩溃,覆盖其他变量或......如果你想扫描整个字符串,你必须定义一个像char s[1024];这样的数组并调用scanf("%s,s)。如果要扫描单个字符,请致电scanf("%c",&amp;a);
      2. scanf()printf("%s",...) 中的链接用于打印整个字符串,因此需要char * 参数。这就是为什么它在第一个示例中没有打印任何内容(实际上它又是未定义的行为)。要打印单个字符,请致电printf("%c",a);

      【讨论】:

        【解决方案3】:

        如果您想在char 中读取,则正确的格式说明符是%c 而不是%s

        【讨论】:

        • 我想读取一个字符串然后打印它。这就是我使用 %s 的原因。为什么在 printf 语句中放置 & 打印字符串,而不放置它不会打印任何内容
        【解决方案4】:

        在 C 中,每个变量都有自己的地址。当我们想读东西时,我们分别发送地址(我们使用&amp;从变量中获取地址)。

        原因是,scanf() 需要修改 a 和 b 的值,但它们是 scanf() 本地的。

        所以为了反映主函数的变量a和b的变化,我们需要传递它们的地址。我们不能简单地按值传递它们。

        示例:

        scanf("%d %d", &a, &b);
        

        但是,在 printf() 函数的情况下,因为我们只在输出控制台中打印变量的值,变量 a 和 b 的值不会发生变化。所以不需要发送他们的地址。

        printf() 示例:

        printf("%d %d", a, b);
        

        (另外,如果您想扫描 char,则必须使用 %c 而不是 %s)

        【讨论】:

        • 但是如果我在 printf() 中不使用 & 它不会给出任何输出。而如果我使用 & 它完美地打印它为什么会发生这种情况?
        • C 中没有string 类型的数据。char 只能保存一个符号。当您使用%sscanf() 扫描时,读取所有世界(到第一个空间)并保存在内存中。但只有第一个字符存储在变量中。您应该使用数组来保存字符串(字符串只是一个字符数组)。首先您必须创建char array[100],然后您可以将字符串保存到其中(记住,字符串末尾必须有'\0')。然后您可以使用getsfgets 来读取和保存字符串。示例:fgets(array, 100, stdin);.
        • array 是数组的名称,100 - 可以保存的最大元素数,结束 stdin - 输入流。阅读更多关于 fgets 你可以there
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-08
        • 1970-01-01
        • 2016-02-07
        • 1970-01-01
        • 2014-04-10
        • 2014-10-06
        • 1970-01-01
        相关资源
        最近更新 更多