C 2D数组作为指向字符数组的指针

C 2D数组作为指向字符数组的指针,c,arrays,pointers,C,Arrays,Pointers,我正在玩一些C语言的代码,同时我也试图理解指针和数组之间的关系。您可能知道,当我想制作阵列时,可以这样做: char * arr = "abc"; char *name[3]; for(int i=0;i<3;i++) { name[i]=malloc(strlen(string)+1); } 或 但是当我想做二维数组的时候。必须这样做 char arr[3][10]; 为什么在我尝试加载字符串时这样的声明会崩溃 char * names[3]; for ( int i = 0;

我正在玩一些C语言的代码,同时我也试图理解指针和数组之间的关系。您可能知道,当我想制作阵列时,可以这样做:

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

但是当我想做二维数组的时候。必须这样做

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] );
}
char*名称[3];
对于(int i=0;i<3;i++){
printf(“输入名称%d:,i+1);
scanf(“%s”,名称[i]);
}
//打印姓名
printf(“\n输入的名称为:\n”);
对于(int i=0;i<3;i++){
printf(“%s\n”,名称[i]);
}

应该是2D数组,对吗?因为数组基本上是指针。 你能解释一下吗?
谢谢。

char*names[3]
并不是严格意义上的2D数组(它们在C或C++中不存在);这是一个数组的数组。因此名称的每个元素只包含一个未初始化的
char*

还要注意,c样式字符串是以null结尾的字符数组,因此原始的
arr
不是c样式字符串。要使其成为c样式字符串,您需要:

char arr[] = {'a','b','c',0};
使其成为长度为4而不是3的数组

缺少空终止符将意味着大多数函数将在分配内存的末尾运行,因为它们不知道字符串何时停止

char * names[3];
不是2D数组,它是指向
char
的三个指针的数组,如果要在其中存储
char数组
,则必须为每个指针分配内存,例如:

for(size_t i = 0; i < 3; i++){
    names[i] = malloc(/*length your array of chars*/);
}
请注意,您必须小心使用
scanf
,如果输入的字符串比分配用于存储它的内存长,则会发生堆栈崩溃,即对于大小为
30
名称[i]
,您应该使用
%29s
说明符,而不是
%s
。虽然这种方法并没有消除它的问题,即可能的字符留在
stdin
buffer中,但它确实更安全

或者,您可以为它们分配字符串文字(在这种情况下,最好将数组声明为
const
,否则,如果尝试编辑一个或多个字符,将导致segfault):


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

所以,要以正确的方式使用指针,它必须始终指向堆栈中的有效内存位置或堆中动态分配的内存

这个
char*names[3]
是一个指针数组,因此您需要为它保留内存,然后对其进行初始化。您需要使用类似于以下的东西:

char * arr = "abc";
char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}
char*name[3];
对于(int i=0;i
它不是指针,而是指针数组

char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;
现在它是指向2D数组的指针。只需定义一个函数,并尝试将它与“指针”一起用作参数

void print_names(char names[][10], const int row){
    for(int i=0; i<row; i++)
      puts(names[i]);
}

你会看到区别。

字符*名称[3];
的崩溃实际上取决于你如何使用它。你用这个数组做什么?这个数组应该解决什么问题?细节:“当我想制作数组时,可以这样做:
字符arr*=“abc”
”.-->这里的
arr
是指针,而不是数组,String literal
“abc”
是数组。“因为数组基本上是指针”-->不是这样。数组就像有许多单元的公寓楼。指针就像单元的地址。我可以轻松地把写在纸上的地址放在口袋里。我无法携带单元。
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