【问题标题】:1D array vs 2D arrays printing strings in c一维数组与二维数组在c中打印字符串
【发布时间】:2017-10-28 05:18:43
【问题描述】:

我知道要打印一个字符串,我们使用

char *pt = "Hi there";
printf("%s", pt);

char pt[] = "Hi there";
printf("%s", pt);

其中数组名的作用就像一个指向第一个元素地址的指针。

但是,例如,当我们得到一个二维数组时,要打印一个字符串,我们必须先取消对该数组的引用,然后才能打印该字符串。

char b[2][10];
strcpy(b[0], "banana");
strcpy(b[1], "apple");
printf("%s", *(b+1));

我想知道为什么我们必须在打印字符串之前先取消引用数组,因为在第一种情况下,我们可以通过将 char 数组的地址提供给 printf 来打印字符串。

但是在第二种情况下,我们已经有了第二个字符串“apple”的地址,那么为什么我们必须先取消引用指针 (b+1),然后才能 printf 里面的值?

【问题讨论】:

  • 你可以写printf("%s", b[1]);,因为b是一个二维数组,b[1]是一个一维数组,它和你现在的第一个例子一样

标签: c arrays pointers


【解决方案1】:

C 中的多维数组有点微妙。 bb[0] 都解析到相同的物理地址是正确的,但是它们具有不同的数据类型,这会影响例如指针添加的工作方式。另外,请注意*(b+1)b[1] 相同。

数组b 衰减为类型char (*)[10],它是一个指向10 个数组char 的指针。因此,如果您添加一个,它会添加10 * sizeof(char)。但是b[0] 会衰减为char *,所以如果你添加一个,它会添加sizeof(char)。取消引用实际上并不转换为内存操作,而是更像类型转换。

【讨论】:

  • 很好的答案,但要返工 “取消引用实际上并没有转化为内存操作,而是更像是类型转换。” 因为它与该段的第一句话说的是什么。有点过。它确实以一种类似于强制转换的方式起作用,但它当然也是一种内存操作(引用)。正如您所说,它提供了一个指向字符数组type char (*)[10] 的指针。
  • @DavidC.Rankin 关键是从bb[0] 时不会生成任何代码。地址相同,但类型不同。请记住,在访问b[i][j] 时,会执行单个 内存加载,而不是两个(就像一维数组一样)。这就是我要说的。这与例如指向char 的指针数组形成对比,后者需要两次内存负载才能访问。
  • 这就是为什么我投票给你但放弃了评论。我知道你在说什么,但我试图找出一种可能不会让不知道的人挠头说“我正在取消引用,但它不是记忆操作,它更像是一个演员.. ?”这是完全正确的,但是取消引用提供了存储在地址中的值也是正确的,在这种情况下,它恰好是所谓的二维数组中的数组(在数组数组中)的开头。我想这是最让人心痛的“不是记忆操作”。
  • @DavidC.Rankin b[0] 未存储在内存中,并且不会产生任何代码。请记住,二维数组是打包的。内存中没有存储指针。它们与指针数组非常不同,尽管对它们的引用在语法上是相同的。所以char x[2][10] 是20 个char 的压缩序列,但char *x[2] 是两个char * 的数组,char **x 是指向char * 的单个指针。这三个都可以作为x[i][j]访问,但第一个是单次加载,第二次是两次加载,第三次最多是三次加载(如果x在内存中)。
  • 每一个错误都是另一个地址或值的加载。 (当然,我们正在考虑寄存器加载取消引用的结果)。我想最重要的一点是,每次取消引用都会提供一个新的地址、类型或值。关键是要知道在给定手头对象的情况下取消引用的行为。获得指向行的指针允许将每一行视为一个 char 数组。无论是由b[0] 还是&b[0][0] 完成,结果都是一样的,但是第一个你有一个指向行的指针,第二个你有一个指向类型的指针。我想这很清楚,因为它需要。干得好。
猜你喜欢
  • 1970-01-01
  • 2014-12-21
  • 2015-12-13
  • 2017-12-29
  • 1970-01-01
  • 2016-02-15
  • 2018-12-02
  • 1970-01-01
相关资源
最近更新 更多