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

如何在C编程中正确终止字符串?,c,C,我正在使用scanf扫描5个产品名称,并将它们存储在一个字符串中。但是,当我打印它们时,最后一个总是打印为♣. 我哪里做错了 我试图在id,名称和5个产品的价格,并打印他们使用的结构。但是,最后一个产品名称始终打印为♣. 我意识到这可能是由于字符串的不当终止,并尝试了针对此类问题提供的解决方案。 我在字符串上看到了另一个类似的问题,并尝试通过这样做来正确终止字符串,char name[50]={'0'};在我的代码中。这部分在代码的结构部分中 struct product { int

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

我试图在id,名称和5个产品的价格,并打印他们使用的结构。但是,最后一个产品名称始终打印为♣. 我意识到这可能是由于字符串的不当终止,并尝试了针对此类问题提供的解决方案。 我在字符串上看到了另一个类似的问题,并尝试通过这样做来正确终止字符串,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,应该是我输入的,但是,♣. 如果我试图通过输入以下命令来终止代码:char name[50]={'\0'};
它在“=”上显示一条错误消息,表示它需要一个“;”

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

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

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

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

笔记: 如果您想在字符串中存储NUL,您可以执行以下操作:;假设您知道字符串的结束位置,则:

 p[i].name[len] = `\0`;
可以声明和初始化字符数组,使其所有元素都为0:

 char name[50] = { '\0' };
但是不能在结构的定义中放入初始化器。结构声明只定义复合对象的一般形式;它没有声明该对象的任何实例,因此没有需要初始化的内容


看起来很棒。请记住,数组从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的更多信息->

不要忘记C中的所有数组索引都是基于零的。也就是说,由5个元素组成的数组的索引范围为0到4(包括0到4);void main不管某些编译器(例如visual studio)允许什么,main只有两个有效签名:int main void和int main int argc,char*argv[]发布的代码无法编译!除其他事项外,还缺少所需头文件的必需include语句。您希望我们猜测您实际包含哪些头文件吗?关于:scanf%d%s%d,&p[i].id,&p[i].name,&p[i].price;在C语言中,对数组名(如“name[])的引用降级为数组第一个字节的地址。因此,此参数:&p[i].name请求的地址不是您想要的地址。建议:p[i].name。注意没有`&’。你的编译器应该告诉你这件事:关于:scanf%d%s%d,&p[i].id,&p[i].name,&p[i].price;调用任何scanf系列函数时,始终检查返回值而不是参数值。“输入格式说明符”数量以外的任何其他值都表示错误,除非价格与名称在单独的一行,且必须与id或空名称在同一行,否则fgets提案将不起作用,并且价格解析将失败。和&p[i]。名称的类型错误;那应该是p[i].name。不管怎样,关于零基索引的第一部分是正确的。corret,非常感谢!非常感谢。这解决了我的许多疑问,而且很容易理解。感谢您花时间这么做。
#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);
}