C 循环中的结构数组
我在学习C语言,我在玩弄结构,但我发现了一些我无法解释的行为,我想知道为什么会发生 这是我的代码:C 循环中的结构数组,c,arrays,loops,struct,C,Arrays,Loops,Struct,我在学习C语言,我在玩弄结构,但我发现了一些我无法解释的行为,我想知道为什么会发生 这是我的代码: struct my_struct{ char *name; }; int main() { struct my_struct arr[3]; int i = 0; char str[10]; while (i<3) { fgets(str, 10, stdin); arr[i].name = str; printf("Array numb
struct my_struct{
char *name;
};
int main()
{
struct my_struct arr[3];
int i = 0;
char str[10];
while (i<3)
{
fgets(str, 10, stdin);
arr[i].name = str;
printf("Array number %d: %s", i, arr[i].name);
i++;
}
printf("1 - %s\n2 - %s\n3 - %s", arr[0].name, arr[1].name, arr[2].name);
return 0;
}
预期产出:
Array number 0: test1
Array number 1: test2
Array number 2: test3
1 - test1
2 - test2
3 - test3
结果输出:
Array number 0: test1
Array number 1: test2
Array number 2: test3
1 - test3
2 - test3
3 - test3
结果输出:
Array number 0: test1
Array number 1: test2
Array number 2: test3
1 - test3
2 - test3
3 - test3
问题是,只要while循环继续运行,它似乎就可以了;但是,当它退出时,它似乎将数组中结构的每个“name”值设置为最后一个值
如果退出循环后,在最后一个printf()之前,我手动设置数组中最后一个结构的名称,这是唯一更新的结构,但以前的结构的名称仍然设置为在循环中输入的最后一个
我想我错过了一些关于内存管理的东西,比如在再次调用fgets()之前刷新缓冲区之类的东西,但是我想不出发生了什么。有人知道这是怎么回事吗?这就是你所期望的,这样想,你有
char str[10]
,这是存储字符串的内存。当您使用arr[i].name=str设置每个数组名时,您将char*name
指向该内存。下面是for循环的作用:
0. str = []; arr[0].name = NULL; arr[1].name = NULL; arr[1].name = NULL;
1. str = [string1]; arr[0].name = str; arr[1].name = NULL; arr[1].name = NULL;
2. str = [string2]; arr[0].name = str; arr[1].name = str; arr[1].name = NULL;
3. str = [string3]; arr[0].name = str; arr[1].name = str; arr[1].name = str;
因此,在循环结束时,所有arr.name
指针都指向字符串,您每次都编辑了字符串。如果希望单个arr
元素存储它们自己的字符串,那么最好这样做:
struct my_struct{
char name[10]; // Note how each instance of `my_struct` now stores its own string.
};
int main() {
struct my_struct arr[3];
int i = 0;
while (i<3) {
fgets(arr[i].name, 10, stdin);
printf("Array number %d: %s", i, arr[i].name);
i++;
}
printf("1 - %s\n2 - %s\n3 - %s", arr[0].name, arr[1].name, arr[2].name);
return 0;
}
struct my\u struct{
char name[10];//注意“my_struct”的每个实例现在如何存储自己的字符串。
};
int main(){
struct my_struct arr[3];
int i=0;
虽然(i这是您所期望的,请这样想,您有char str[10]
,这是存储字符串的内存。当您使用arr[i].name=str
设置每个数组名时,您将char*name
指向此内存。下面是for循环的操作:
0. str = []; arr[0].name = NULL; arr[1].name = NULL; arr[1].name = NULL;
1. str = [string1]; arr[0].name = str; arr[1].name = NULL; arr[1].name = NULL;
2. str = [string2]; arr[0].name = str; arr[1].name = str; arr[1].name = NULL;
3. str = [string3]; arr[0].name = str; arr[1].name = str; arr[1].name = str;
因此,在循环结束时,所有的arr.name
指针都指向字符串,您每次都编辑了字符串。如果您希望单个arr
元素存储自己的字符串,那么最好这样做:
struct my_struct{
char name[10]; // Note how each instance of `my_struct` now stores its own string.
};
int main() {
struct my_struct arr[3];
int i = 0;
while (i<3) {
fgets(arr[i].name, 10, stdin);
printf("Array number %d: %s", i, arr[i].name);
i++;
}
printf("1 - %s\n2 - %s\n3 - %s", arr[0].name, arr[1].name, arr[2].name);
return 0;
}
struct my\u struct{
char name[10];//注意“my_struct”的每个实例现在如何存储自己的字符串。
};
int main(){
struct my_struct arr[3];
int i=0;
while(i您不能像那样复制C字符串arr[i].name=str
您所做的是将每个名称指针设置为相同的地址,由str
表示。因此,当您调用printf
时,每个name
指向相同的字符串,str
,而printf
只需打印str
三次
如果要复制字符串,请使用strcpy。此外,还需要为name
变量分配内存。您不能像那样复制C字符串arr[i]。name=str
您所做的是将每个名称指针设置为相同的地址,由str
表示。因此,当您调用printf
时,每个name
指向相同的字符串,str
,而printf
只需打印str
三次
如果要复制字符串,请使用strcpy。此外,还需要为名称
变量分配内存。必须为每个结构的char*名称分配内存:
while (i<3)
{
fgets(str, 10, stdin);
arr[i].name=(char *)malloc(10*sizeof(char));
strcpy(arr[i].name,str);
printf("Array number %d: %s", i, arr[i].name);
i++;
}
while(i您必须为每个结构的char*名称分配内存:
while (i<3)
{
fgets(str, 10, stdin);
arr[i].name=(char *)malloc(10*sizeof(char));
strcpy(arr[i].name,str);
printf("Array number %d: %s", i, arr[i].name);
i++;
}
while(i因为这是C,所以您需要自己管理所有的内存构造/销毁/管理
如果您只是在学习C,那么现在最好还是坚持使用字符数组,而不是直接使用指针,除非您知道自己在做什么,或者至少事先不做一点研究/学习
数组不同于指针,有一篇文章详细介绍了它们之间的区别
针对您的问题,您可以通过向代码添加多一点输出来更清楚地了解发生了什么。使用%p
格式说明符,您可以打印出变量的指针位置
有几种方法可以调试C程序来解决这个问题,比如在Linux上使用gdb
,或者在Windows上使用Visual Studio,但这是在这里显示的最简单的方法
将一些调试输出添加到程序中,可以得到以下结果:
#include<stdio.h>
struct my_struct{
char *name;
};
int main()
{
struct my_struct arr[3];
int i = 0;
char str[10];
while (i<3)
{
fgets(str, 10, stdin);
arr[i].name = str;
printf("Array number %d: %s", i, arr[i].name);
printf(" %p\n", arr[i].name);
i++;
}
printf("\n1 - %s (%p)\n2 - %s (%p)\n3 - %s (%p)",
arr[0].name, arr[0].name,
arr[1].name, arr[1].name,
arr[2].name, arr[2].name);
return 0;
}
从这一点上,我们可以看出,您每次都在明显地覆盖相同的内存地址。这是因为name
被分配给str
,更迂腐的是,name
被设置为char*
str
在内存中存在的位置,这可能不会改变。这与在循环中执行三次x=3
基本相同
要解决这个问题,您需要做两件事
分配每个arr[i]。在使用前命名实例。这可以通过stdlib.h
中的malloc
或calloc
实现
将从stdin
检索到的输入复制到arr[i].name
中。这可以使用strcpy
或strncpy
从string.h
应用修复程序(两行代码)后,循环将如下所示:
while (i<3)
{
fgets(str, 10, stdin);
// Allocate 10 (most likely) bytes of memory to arr[i].name
// And also clear out that memory space
arr[i].name = (char*)calloc(10, sizeof(char));
// Safely copy the data (max 10 chars) from 'str' into 'arr[i].name'
strncpy(arr[i].name, str, 10);
printf("Array number %d: %s", i, arr[i].name);
printf(" %p\n", arr[i].name);
i++;
}
因为这是C,所以您需要自己管理所有的内存构造/销毁/管理
如果您只是在学习C,那么现在最好还是坚持使用字符数组,而不是直接使用指针,除非您知道自己在做什么,或者至少事先不做一点研究/学习
数组不同于指针,有一篇文章详细介绍了它们之间的区别
针对您的问题,您可以通过向中添加多一点输出来更清楚地了解发生了什么