C 中指向 char 数组的指针存在问题

问题描述 投票:0回答:1

我用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()
,如果我尝试打印数组中的名称,它将带有外部字符串:

enter image description here

我认为发生这种情况是因为保存在数组

names
中的指针在从
main()
返回到
addNames()
时被“销毁”,因为这些指针是在那里创建的。

对于任何拼写错误或冗余,我深表歉意,我不是母语人士 xD。希望您能帮助了解发生了什么,以及我该如何解决这个问题,或者哪种方法效果更好。谢谢

arrays c string module char
1个回答
0
投票

您正在处理一些有趣的问题。

数组大小 ≠ 使用的元素数量

首先,您的数组具有声明的大小,并且您要求用户为您提供那么多名称。我建议您跟踪实际使用的名称数量,并让用户有机会提供更少的名称。

char* names[MAX_NAMES];
int num_names = 0;

strdup()

现在,要将名称添加到您的列表中,只需:

    // 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;
}

strcpy()

您可以使用字符串数组,而不是指针数组。

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()
任何事情。

fgets() 和换行符

作为附录,您应该检查输入操作的结果以验证它们是否有效。

    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);

}

变化比比皆是,但要点是您已将名称(和名称计数)数据从全局对象移动到可以本地化的对象。

© www.soinside.com 2019 - 2024. All rights reserved.