我用C编写了以下代码:
#include <stdio.h>
#include <string.h>
#define MAX_NAMES 5
#define MAX_NAME_LENGTH 20
char* names[MAX_NAMES];
void addNames();
int main(){
addNames();
printf("\n");
for(int i=0; i<MAX_NAMES; i++){
// printing "name" from array
printf("Name from array #%d: %s\n", i+1, names[i]);
}
return 0;
}
void addNames(){
char name[MAX_NAME_LENGTH];
for(int i=0; i<MAX_NAMES; i++){
printf("Give me the name #%d: ", i+1);
fgets(name, MAX_NAME_LENGTH, stdin);
name[strlen(name)-1]='\0';
// adding "name" to array "names"
names[i]=name;
// printing "name" from array
printf("Name given: %s\n", names[i]);
}
}
它声明了一个指向字符数组(
names
)的指针类型的全局变量char*
。在 addNames()
一切正常。我可以将用户的输入存储在 name
类型的变量 char[MAX_NAME_LENGTH]
中,然后将其保存到数组 names
并打印名称。
但是一旦我离开 addNames()
模块并返回到 main()
,如果我尝试打印数组中的名称,它将带有外部字符串:
我认为发生这种情况是因为保存在数组
names
中的指针在从main()
返回到addNames()
时被“销毁”,因为这些指针是在那里创建的。
对于任何拼写错误或冗余,我深表歉意,我不是母语人士 xD。希望您能帮助了解发生了什么,以及我该如何解决这个问题,或者哪种方法效果更好。谢谢
您正在处理一些有趣的问题。
首先,您的数组具有声明的大小,并且您要求用户为您提供那么多名称。我建议您还跟踪实际使用的名称数量,并让用户有机会提供更少的名称。
char* names[MAX_NAMES];
int num_names = 0;
现在,要将名称添加到您的列表中,只需:
// add a dynamically-allocated copy of name to the end of our list of names
names[num_names++] = strdup(name);
如果您使用
strdup()
,您还必须 free()
使用的名称:
int main(void){
// get the names
addNames();
// print the names
printf("\n");
for(int i=0; i<num_names; i++){
printf("Name from array #%d: %s\n", i+1, names[i]);
}
// free the names
for(int i=0; i<num_names; i++){
free(names[i]);
}
return 0;
}
您可以使用字符串数组,而不是指针数组。
char names[MAX_NAMES][MAX_NAME_LENGTH];
int num_names = 0;
现在您可以使用
strcpy()
复制从用户处获得的字符串。
// copy the name to the end of our list of names
strcpy(names[num_names++], name);
有了这个,您不再需要
free()
任何事情。
作为附录,您应该检查输入操作的结果以验证它们是否有效。
if (!fgets(name, MAX_NAME_LENGTH, stdin)) crash_and_burn();
char * nl = strpbrk(name, "\n\r");
if (!nl) crash_and_burn();
*nl = '\0';
如果尝试读取文件失败,则程序应该失败。
同样,如果用户提供的行太长,程序就会失败。
原因很简单:如果用户没有提供正确的输入,就会导致程序失败。要求用户提供正确的输入!
人们会让你对全局变量感到悲伤。它们并不像每个人都喜欢重复的那样邪恶,但“全局是邪恶的”这句话是在说你应该考虑它们的影响。
对于家庭作业解决方案来说,没什么大不了的。对于很多程序来说,没什么大不了的。
当事情开始变得复杂时,全球化开始让生活变得比需要的更加困难。
因此,对于未来,您应该开始考虑在不使用全局变量的情况下实现此目的的方法。例如,您可以将函数签名重写为:
int add_names(char* names[]);
```or:
```C
int add_names(char names[][MAX_NAME_LENGTH]);
然后在
main()
中你可以得到的名称为:
int main(void){
char* names[MAX_NAMES] = {NULL};
int num_names = 0;
num_names = add_names(names);
}
变化比比皆是,但要点是您已将名称(和名称计数)数据从全局对象移动到可以本地化的对象。