扫描并打印列表中的全名(C语言)

时间:2017-01-18 18:47:59

标签: c

我想创建一个可以读取' n'键盘输入的全名数量并打印出来。我尝试使用fgets(),但无法弄清楚如何扫描多个条目,所以我最终编写了下面的代码。

问题是,它将名称作为输入,只打印垃圾值。

#include <stdio.h>
#include <conio.h>
#include <string.h>

int main()
{
    int n,i;
    char name[64][64],sur[15][15],a[3];

    printf("How many names? ");
    scanf("%d",&n);
    printf("\nEnter names:\n");

    for(i=0;i<n;i++)
    {
        scanf("%s%s",name[i],sur[i]);
    }

    for(i=0;i<n;i++)
    {
        a[3]=' ';
        strcat(name[i],a);
        strcat(name[i],sur[i]);
    }

    printf("\nThe names are:\n");
    for(i=0;i<n;i++)
    {
        printf("%s",name[i]);
    }
    getch();

    return 0;
}

2 个答案:

答案 0 :(得分:1)

@16tons addresses the most obvious issue,但存在潜伏的记忆问题。 scanfstrcat来电可能会受到buffer overflows攻击。他们不会仅限于分配的内存。

for(i=0;i<n;i++)
{
    scanf("%s%s",name[i],sur[i]);
}

这会尝试将任意数量的输入字符放入name[i]sur[i],这些字符只能分别包含63和14个字符的字符串。这意味着Hubert Wolfe­schlegel­stein­hausen­berger­dorff会导致name[i]包含"Hubert\0"sur[i]将包含"Wolfe­schlegel­st"(无空字节),其余的将溢出到相邻的内存中导致问题。由于缺少空字节,尝试将sur[i]用作字符串将导致读取其后的垃圾。

strcat相同。

for(i=0;i<n;i++)
{
    a[0]=' ';
    a[1]='\0';
    strcat(name[i],a);
    strcat(name[i],sur[i]);
}

如果name[i]已经满了,添加到它的末尾将溢出其缓冲区在相邻内存上划线并导致奇怪的问题。

How many names? 3

Enter names:
Hubert Wolfeschlegelsteinhausenbergerdorff
Hubert Wolfeschlegelsteinhausenbergerdorff
Hubert Wolfeschlegelsteinhausenbergerdorff

The names are:
Hubert WolfeschlegelstWolfeschlegelstWolfeschlegelsteinhausenbergerdorff WolfeschlegelstWolfeschlegelsteinhausenbergerdorff
gerdorff WolfeschlegelstWolfeschlegelsteinhausenbergerdorff
Hubert Wolfeschlegelsteinhausenbergerdorff

为避免这种情况,scanf必须限制为缓冲区大小。使用strcat时,添加的字符串必须有足够的空间来接受新字符。

由于您使用name[i]来存储名字和全名,因此限制名字的大小以便最后留出空间非常重要。由于sur[i]可以包含14个字符,name[i]可以包含63个字符,因此63 - 14或49.不要忘记空间! 48。

for(i=0;i<n;i++)
{
    scanf("%48s%14s",name[i],sur[i]);
}

这可确保scanfname[i]读取不超过48个字符(由于空字节使用49个字节),并且sur[i](使用15)不超过14个字符。

现在您的strcat是安全的。我们确信name[i]有空间可以接受空格,最后可以sur[i]。 48(最大字符已在name[i])+ 1(空格)+14(最大值在sur[i])+ 1(空字节)= 64。

虽然您的技术可以节省一些内存,但 更安全,可以将单独的givensurname变量连接到一起一个新的name变量。然后,您需要做的就是添加givensurname的大小和空格,以了解name应该有多大。 scanf的限制只是缓冲区的大小。不需要记住,如果surname变大,一个变量必须保留一些额外的空间,也不必重做所有这些计算(或者更可能忘记重做它们)。

出于特定目的,strcat是不必要的。 printf可以做得更安全。

printf("\nThe names are:\n");
for(i=0;i<n;i++)
{
    printf("%s %s\n",name[i], sur[i]);
}

将一堆变量打印到流中比将它们连接在一起然后打印它们更安全,更容易,更快捷。

答案 1 :(得分:0)

如评论中所述,使用a[0]作为空格并使a[1]为空。以下代码有效。

int main()
{
    int n,i;
    char name[64][64],sur[15][15],a[3];

    printf("How many names? ");
    scanf("%d",&n);
    printf("\nEnter names:\n");

    for(i=0;i<n;i++)
    {
        scanf("%s%s",name[i],sur[i]);
    }

    for(i=0;i<n;i++)
    {
        a[0]=' ';
        a[1]='\0';
        strcat(name[i],a);
        strcat(name[i],sur[i]);
    }

    printf("\nThe names are:\n");
    for(i=0;i<n;i++)
    {
        printf("%s\n",name[i]);
    }
    getch();

    return 0;
}