如何在C编程中正确终止字符串?

时间:2019-07-08 15:13:25

标签: c

我正在使用scanf扫描5个产品名称并将它们存储在字符串中。但是,当我打印它们时,最后一个总是打印为♣。我要去哪里错了?

我正在尝试输入5种产品的ID,名称和价格,并使用结构进行打印。但是,最后一个产品名称始终打印为♣。我意识到这可能是由于字符串的不正确终止造成的,因此尝试了针对此类问题的解决方案。 我在字符串上看到了另一个类似的问题,并试图通过这样做正确终止字符串,char name [50] = {'0'};在我的代码中。这部分在代码的结构部分之内。

struct product
 {
    int id;
    char name[50];
    int price;
 };

void main()
 {
    struct product p [5];
    int i,a;
    for(i=1;i<=5;i++)
    {
        printf("Enter the id no., name and price of the product %d\n",i);
        scanf("%d%s%d",&p[i].id,&p[i].name,&p[i].price);
    }
    printf("The id no., name and price of the product %d are\n",i);
    for(i=1;i<=5;i++)
    {
        printf("\t%d\t%s/0\t%d\n",p[i].id,p[i].name,p[i].price);
    }
}

最终的输出是p [5] .name,应该是我输入的,但是是is。 如果我尝试通过输入以下代码来终止代码:char name [50] = {'\ 0'}; 它会在'='上显示一条错误消息,说它期望使用';'。

2 个答案:

答案 0 :(得分:1)

问题不在于字符串终止。 [注1]

您的问题是C中的数组从索引0开始,而不是索引1。因此,p中的元素是p[0]p[4],因此p[5]引用了随机内存。 C不会检查数组索引是否有效,而使用无效的索引会导致像这样的奇怪错误。

scanf当然是NUL终止的字符串,这就是为什么我说终止不是问题。但是,它不知道您为该字符串保留了多少内存,因此如果用户输入的字符串太长,它很可能会覆盖随机内存。最好使用格式"%d%49s%d"(在这种情况下)将字符串读取限制为49个字符。 (您不能将50个字符的字符串精确地容纳在50个元素的数组中,因为您需要为终止NUL留出空间。)

但是,您还需要检查scanf的返回值。该函数返回成功转换的次数,在这种情况下,必须为三。如果返回较小的数字,则表示其中一个转换失败,并且如果数字转换失败,则有问题的字符(也许是字母)仍将是下一个输入字符,因此下一个%d转换也将失败


注意:

  1. 如果要将NUL存储在字符串中,则将执行以下操作;假设您知道字符串的结尾:

    p[i].name[len] = `\0`;
    

    您可以声明并初始化字符数组,使其所有元素均为0:

    char name[50] = { '\0' };
    

    但是您不能在struct的定义中放入初始化程序。 struct声明仅定义复合对象的一般形式;它没有声明该对象的任何实例,因此无需初始化。

答案 1 :(得分:-1)

看起来很棒。请记住,数组从0开始。将for循环更改为索引0-4。

for(i = 0; i < 5; i++)
{
    printf("Enter the id no., name and price of the product %d\n",i);
    scanf("%d%s%d",&p[i].id,&p[i].name,&p[i].price);
}

通常,我强烈建议使用fgets从用户输入字符串,以避免scanf的风险,并在末尾添加NULL。

#include <string.h>

for(i = 0; i < 5; i++)
{
    printf("Enter the id no., name and price of the product %d\n",i);
    scanf("%d",&p[i].id);
    fgets(p[i].name, 50, stdin);
    scanf("%d",&p[i].price);
}

有关fgets-> https://www.geeksforgeeks.org/fgets-gets-c-language/

的更多信息