1D数组与2D数组在c中打印字符串
我知道要打印字符串,我们使用1D数组与2D数组在c中打印字符串,c,arrays,pointers,C,Arrays,Pointers,我知道要打印字符串,我们使用 char *pt = "Hi there"; printf("%s", pt); 或 其中,数组名的作用类似于指向第一个元素地址的指针 然而,当我们得到一个2D数组时,例如,要打印一个字符串,我们必须先取消对数组的引用,然后才能打印字符串 char b[2][10]; strcpy(b[0], "banana"); strcpy(b[1], "apple"); printf("%s", *(b+1)); 我想知道为什么在打印字符串之前必须先取消对数组的引用,因为
char *pt = "Hi there";
printf("%s", pt);
或
其中,数组名的作用类似于指向第一个元素地址的指针
然而,当我们得到一个2D数组时,例如,要打印一个字符串,我们必须先取消对数组的引用,然后才能打印字符串
char b[2][10];
strcpy(b[0], "banana");
strcpy(b[1], "apple");
printf("%s", *(b+1));
我想知道为什么在打印字符串之前必须先取消对数组的引用,因为在第一种情况下,我们可以通过向printf提供字符数组的地址来打印字符串。然而,在第二种情况下,我们已经有了第二个字符串“apple”的地址,那么为什么我们必须先取消对指针(b+1)的引用,然后才能打印里面的值呢?C中的多维数组有点微妙。您认为
b
和b[0]
解析为相同的物理地址是正确的,但它们具有不同的数据类型,例如,这会影响指针添加的工作方式。另外,请注意*(b+1)
与b[1]
相同
数组
b
衰减为类型char(*)[10]
,它是指向10char
数组的指针。因此,如果向其中添加一个,它将添加10*sizeof(char)
。但是b[0]
会衰减为类型char*
,因此如果向其中添加一个,它会添加sizeof(char)
。解引用实际上并没有转化为内存操作,而是更像一个类型转换。回答得好,但“解引用实际上并没有转化为内存操作,而是更像一个类型转换。”因为它和该段第一句所说的有些冲突。有点不对劲。它确实以一种类似于强制转换的方式工作,但它当然也是一种内存操作(引用)。它提供了一个指向字符数组type char(*)[10]
的指针,正如您所说。@DavidC.Rankin好的,关键是从b
到b[0]
时不会生成任何代码。地址相同,但类型不同。请记住,当访问b[i][j]
时,只执行一次内存加载,而不是两次(就像一维数组一样)。这就是我要说的。例如,这与指向char
的指针数组不同,后者需要两次内存加载才能访问。这就是为什么我投票支持你,但放弃了评论。我知道你在说什么,但我试图找出一种方法,不让不知道的人挠头说“我在解引用,但这不是一个内存操作,更像是一个cast…”这是完全正确的,但解引用提供了存储在地址中的值,在本例中,它恰好是一个数组(在数组数组中)的开始,在所谓的2D数组中。我想最让人心痛的是“非内存操作”。@DavidC.Rankinb[0]
没有存储在内存中,也不会生成代码。记住,二维数组是压缩的。内存中没有存储指针。它们与指针数组非常不同,尽管对它们的引用在语法上是相同的。所以char x[2][10]
是一个由20个char
组成的压缩序列,但是char*x[2]
是一个由两个char*
组成的数组,char**x
是指向char*
的单个指针。所有三个都可以作为x[i][j]
访问,但第一个是单次加载,第二个是两次加载,第三个最多是三次加载(如果x
在内存中)。每次撤销都是另一个地址或值的加载。(当然,我们正在考虑取消引用的结果)。我想最重要的一点是,每次取消引用都会提供一个新的地址、类型或值。关键是要知道,给定手头的对象,解引用的行为如何。获取指向行的指针可以将每一行视为一个字符数组。无论是通过b[0]
还是通过&b[0][0]
完成,结果都是相同的,但第一个指针指向行,第二个指针指向类型。我想这是一个明确的,因为它需要。干得好。您可以编写printf(“%s”,b[1])
由于b
是一个二维数组,b[1]
是一个一维数组,它与您现在的第一个示例完全相同
char b[2][10];
strcpy(b[0], "banana");
strcpy(b[1], "apple");
printf("%s", *(b+1));