缺少一个应该在 C 中打印的字符

Missing a character that is supposed to print in C

我正在编写这个简单的代码来获取一些学生的证书作为使用 C 的示例,并且我能够打印除我的名字之外的所有其他内容。据我所知,代码似乎是正确的,但无论顺序如何,我的名字都没有打印出来。我只是C语言和Stack Overflow的初学者,所以,如果我犯了一些错误,请多多包涵。

#include<stdio.h>
void main()
{
    char name[10],age[2],add[50],gradyear[50];
    printf("Enter your Name:");
    scanf("%[^\n]%*c", name);
    printf("Enter your Age:");
    scanf("%[^\n]%*c", age);
    printf("Enter your Address:");
    scanf("%[^\n]%*c", add);
    printf("Enter your Year of Graduation:");
    scanf("%[^\n]%*c", gradyear);
    printf("Here are your student credentials:\nName:%s \nAge:%s \nAddress:%s \nYear of Graduation:%s ",name,age,add,gradyear);
}

为了把问题弄清楚,我在原代码中加了一些调试代码
这确实是解决这个问题的正确地方,因为它是由 overflow.

引起的
#include<stdio.h>
int main(void)
{
    char name[10],age[2],addr[50],gradyear[50];

    /* Debugging Code Begin */
    printf("name\t\t: %p %p\n", (void *)name, (void *)(name+9));
    printf("age\t\t: %p %p\n", (void *)age, (void *)(age+1));
    printf("addr\t\t: %p %p\n", (void *)addr, (void *)(addr+49));
    printf("gradyear\t: %p %p\n", (void *)gradyear, (void *)(gradyear+49));
    /* Debugging Code End */

    printf("Enter your Name:");
    scanf("%[^\n]%*c", name);
    printf("Enter your Age:");
    scanf("%[^\n]%*c", age);
    printf("Enter your Address:");
    scanf("%[^\n]%*c", addr);
    printf("Enter your Year of Graduation:");
    scanf("%[^\n]%*c", gradyear);
    printf("Here are your student credentials:\n"
           "Name:%s \nAge:%s \nAddress:%s \nYear of Graduation:%s \n"
           , name, age, addr, gradyear);
}

用gcc(GCC 11.2.0)编译时,调试输出为:

name        : 0x7ff7b92ca726 0x7ff7b92ca72f
age         : 0x7ff7b92ca724 0x7ff7b92ca725
addr        : 0x7ff7b92ca6f0 0x7ff7b92ca721
gradyear    : 0x7ff7b92ca6b0 0x7ff7b92ca6e1

我们可以看到,age的第二个字节的地址是0x7ff7b92ca725,name的第一个字节的地址是0x7ff7b92ca726。两个地址相邻。
所以当我们输入一个两位或更多位的数字并将其保存在年龄数组中时,就会发生溢出。
例如,当我们scanf一个两位数的长数时,比如25然后age[0]有'2',age[1]有'5'并且Null字符将被存储到第一个字节的名字。
这正是名称字符串显示意外空白的原因。

用clang(clang-1300.0.29.30)编译时,调试输出为:

name        : 0x7ff7bda1271e 0x7ff7bda12727
age         : 0x7ff7bda1269e 0x7ff7bda1269f
addr        : 0x7ff7bda126e0 0x7ff7bda12711
gradyear    : 0x7ff7bda126a0 0x7ff7bda126d1

和上面的情况类似,在这里,我们可以看到age的第二个字节(0x7ff7bda1269f)的地址与gradyear的第一个字节(0x7ff7bda126a0)的地址相邻。当发生溢出时,age的输出是age和gradyear的内容拼接在一起,比如152015

建议和解决方案:永远记得为C风格的字符串(Null-terminated String)添加一个额外的字节。

如果您打算将大小设置为两个,则将数组设置为三个。