指向字符数组的二维数组指针

3

我正在使用C语言编写一些代码,并尝试理解指针和数组之间的关系。正如你可能知道的那样,如果我想创建数组,可以这样做:

char * arr = "abc";

或者

char arr[] = {'a','b', 'c'};

但是当我想要创建一个二维数组时,必须像这样完成

char arr[3][10];

为什么我试图将字符串加载到这个声明中时会崩溃。

char * names[3];

for ( int i = 0; i < 3; i++ ) {
    printf("Enter name %d: ", i+1 );
    scanf("%s", names[i]);
}
// print names
printf("\nEntered names are: \n");
for ( int i = 0; i < 3; i++ ) {
    printf("%s\n", names[i] );
}

这应该是一个二维数组,因为数组本质上是指针。 你能解释一下吗? 谢谢。


2
char *names[3]; 的崩溃情况实际上取决于你如何使用它。你用这个数组做了什么?这个数组应该解决什么问题? - Some programmer dude
当我想要创建一个数组时,可以这样做:char arr* = "abc";。在这里,arr是一个指针,而不是一个数组,字符串字面值"abc"是一个数组。 - chux - Reinstate Monica
1
不是这样。数组就像一个有许多单元的公寓大楼。指针就像单元的地址。我可以轻松地把地址写在口袋里,但我无法搬动这个单元。因此,数组并不基本上是指针。 - chux - Reinstate Monica
4个回答

5
char * names[3];

这不是一个二维数组,而是一个包含三个指向char的指针的数组。如果您想在其中存储char数组,则必须为每个单独的指针分配内存,类似于:

for(size_t i = 0; i < 3; i++){
    names[i] = malloc(/*length your array of chars*/);
}

接下来,您可以存储字符数组,使用您的示例:

for(size_t i = 0; i < 3; i++){
    printf("Enter name %ld: ", i + 1 );
    scanf("%29s", names[i]); //for a malloc size of 30
}

请注意,使用scanf时必须小心,如果输入的字符串长度超过了分配给它存储的内存,则会发生堆栈破坏,即对于大小为30names [i],应该使用%29s指定符,而不是%s。虽然这种方法不是没有问题的,也就是可能在stdin缓冲区中留下一些字符,但这绝对更安全。
或者你可以将它们分配为字符串字面量(在这种情况下,最好将数组声明为const,否则如果尝试编辑一个或多个字符,将导致段错误):
const char* names[3];

for(size_t i = 0; i < 3; i++){
    names[i] = "My string literal";
}

你也可以让它们指向现有的字符数组:
char arr[3][10];
char* names[3];

for(size_t i = 0; i < 3; i++){
    names[i] = arr[i];
}

2
char * names_1[3];

它不是一个指针,而是一个指针数组。

char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;

现在它是指向你的二维数组的指针。只需定义一个函数并尝试将其与您的“指针”作为参数一起使用即可。
void print_names(char names[][10], const int row){
    for(int i=0; i<row; i++)
      puts(names[i]);
}

现在使用以下方式调用:
print_names(names_2, 3); 
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG

你会看到差异。


1

指针是一种变量类型,它只能包含另一个变量的地址。它不能包含任何数据。您不能将数据存储到指针中。指针应该指向内存位置。

因此,为了正确使用指针,它必须始终指向堆栈中的有效内存位置或动态分配在堆中的内存。

这个char * names[3]是一个指针数组,所以你需要为它保留内存并初始化它。您需要使用类似以下内容的东西:

char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}

同时,您还应该为char *arr分配内存。

char *arr=malloc(strlen(data)+1)

然后进行初始化。


1
"

char* names[3]不是严格意义上的二维数组(在C或C++中不存在),它是一个数组的数组。因此,names的每个元素只包含一个未初始化的char*

另外,请注意,C风格的字符串是一个以null结尾的字符数组,所以您原来的arr不是C风格的字符串。要将其变成C风格的字符串,您需要:

"
char arr[] = {'a','b','c',0};

使其成为长度为4的数组,而不是3。
省略空终止符将意味着大多数函数会越过所分配的内存的末尾,因为它们不知道字符串何时停止。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接