当前位置:  开发笔记 > 编程语言 > 正文

我在C中的(char*)元素数组上有三个循环.为什么第三个失败?

如何解决《我在C中的(char*)元素数组上有三个循环.为什么第三个失败?》经验,为你挑选了2个好方法。

在尝试使用C语言中的字符串数组步进的方法时,我开发了以下小程序:

#include 
#include 
#include 


typedef char* string;

int main() {
  char *family1[4] = {"father", "mother", "son", NULL};
  string family2[4] = {"father", "mother", "son", NULL};

  /* Loop #1: Using a simple pointer to step through "family1". */
  for (char **p = family1; *p != NULL; p++) {
    printf("%s\n", *p);
  }
  putchar('\n');

  /* Loop #2: Using the typedef for clarity and stepping through
   * family2. */
  for (string *s = family2; *s != NULL; s++) {
    printf("%s\n", *s);
  }
  putchar('\n');

  /* Loop #3: Again, we use the pointer, but with a unique increment
   * step in our for loop.  This fails to work.  Why? */
  for (string s = family2[0]; s != NULL; s = *(&s + 1)) {
    printf("%s\n", s);
  }
}

我的具体问题涉及Loop#3的失败.当通过调试器运行时,循环#1和#2成功完成,但最后一个循环因未知原因而失败.我不会在这里问这个,除了这个事实表明我对"&"运算符有一些严重的误解.

我的问题(和当前的理解)是这样的:

family2是一个指向char的数组.因此,当s设置为family2[0]我们(char*)指向"父亲"时.因此,服用&s应该给我们相当于family2,指向family2预期指针衰减后的第一个元素.那么,为什么不 *(&s + 1)按预期指向下一个元素呢?

非常感谢,
生活危机


编辑 - 更新和经验教训:

以下列表是所有相关事实和解释的摘要,这些事实和解释解释了为什么第三个循环不像前两个循环那样起作用.

    s是一个单独的变量,它保存变量的值(指向char的指针)的副本family2[0].即,这两个等效值位于内存中的SEPARATE位置.

    family2[0]最多family2[3]是内存的连续元素,并且s在此空间中没有存在,尽管它确实包含在family2[0]循环开始时存储的相同值.

    前两个事实意味着&s并且&family2[0]不相等.因此,添加一个&s将返回指向未知/未定义数据的指针,而添加一个&family2[0]&family2[1]根据需要提供给您.

    此外,第三个for循环中的更新步骤实际上并不会导致在每次迭代时s在内存中前进.这是因为&s在循环的所有迭代中都是恒定的.这是观察到的无限循环的原因.

感谢每个人的帮助!
lifecrisis



1> Some program..:

执行s = *(&s + 1)此操作时,变量s是隐式作用域中的局部变量,仅包含循环.当您这样做时,&s您将获得该局部变量的地址,该地址变量与任何阵列无关.

与前一个循环的不同之处在于,有s一个指向数组中第一个元素的指针.


为了更加"图解"地解释它在最后一个循环中所拥有的东西就像是

+----+      +---+      +------------+
| &s | ---> | s | ---> | family2[0] |
+----+      +---+      +------------+

也就是说,&s指向ss指向family2[0].

当你&s + 1有效地拥有类似的东西时

+------------+
| family2[0] |
+------------+
^
|
+---+----
| s | ...
+---+----
^   ^
|   |
&s  &s + 1


@lifecrisis不,`&s`是指向`s`的指针,没有别的.

2> Spikatrix..:

图片有很多帮助:

            +----------+
            | "father" |                                    
            +----------+         +----------+      +-------+      NULL 
   /-----------?1000            | "mother" |      | "son" |        ?
+-----+           ?              +----------+      +-------+        |
|  s  | ?         |                  2000            2500           |
+-----+           |                   ?                ?            |
 6000  6008 +----------------+----------------+--------------+--------------+
            |   family2[0]   |   family2[1]   |  family2[2]  |  family2[3]  |
            +----------------+----------------+--------------+--------------+
                  5000              5008            5016           5024

                    (    &s refers to 6000    ) 
                    ( &s+1 refers to 6008 but )
                    (   *(&s+1) invokes UB    )

为简单起见,地址被选为随机整数


这里的事情是,虽然两者sfamily2[0]指向字符串的相同的基地址字面"father",指针不互相关联,而且它们的存储自己不同的存储位置.*(&s+1) != family2[1].

你这样做*(&s + 1)是因为你&s + 1是一个你不应该篡改的内存位置,也就是说,它不属于你创建的任何对象.你永远不知道那里存储了什么=>未定义的行为.

感谢@ 2501指出了几个错误!


目前尚不清楚您在这里代表哪个例子.无论如何,这是错误的.&s + 1没有指向任何东西.它甚至不是一个有效的对象.
推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有