将指针分配给指向字符指针的数组

3

gcc 4.4.4 c89

#define SIZE 5
    char *names[SIZE] = {"peter", "lisa", "simon", "sarah", "julie"};
    char *search_names[SIZE] = {0};
    size_t i = 0;

    for(i = 0; i < SIZE; i++ ) {
        search_names[i] = names[i]++;
    }

    for(i = 0; i < SIZE; i++) {
        printf("name to search for [ %s ]\n", search_names[i]);
    }

我对这一行代码 search_names[i] = names[i]++; 感到困惑,它是一个指向 char* 的指针数组。我在试验的时候认为应该改成 &names[i]++,因为我想要得到该位置的指针。因此,使用 & 可以让我获得指针所指向的地址。

我猜我也可以这样增加: (names[i]) + i;

只是对那一行代码感到困惑。


1
我不认为我完全理解你代码的意图。这两个数组都是指向字符的指针数组。你只是将一个数组复制到另一个数组吗?如果是这样,那么它应该只是“search_names[i] = names[i];”。你为什么需要增加呢? - spencer nelson
1
是的,你说得对。我只是在尝试不同的东西。然而,search_names[i] = names[i]; 产生了与 search_names[i] = names[i]++; 相同的结果。这是否意味着它们在某种意义上都是相等的?names[i]++ 会增加什么?谢谢。 - ant2009
2
names[i] 指的是一些字符串,例如 "peter"。在 C 语言中,字符串被存储为字符数组,并以 "\0" 结尾。当你抓取 names[i] 时,实际上是抓取了一个指向字符串中第一个元素的指针,该字符串位于 names[i] 处,换句话说,一个指向 "peter\0" 中 "p" 的指针。当你增加该指针时,它向前移动一个位置,指向 "e",变成了 "eter\0"。不过,由于优先级规则比较晦涩,增量操作是在对 search_names[i] 赋值之后进行的,因此看起来是相同的,但实际上你进行了额外的指针操作。 - spencer nelson
3个回答

7

names[i] 是一个指针,类型为char*&names[i]是一个指向names[i]的指针,因此其类型为char**。下面是一张内存示意图:

names                    for each i, this is where names[i] *points*
|__________________          0     1    2     3     4
|                  |         |     |    |     |     |
|                  |         v     v    v     v     v
[0 ][1 ][2 ][3 ][4 ]  <gap>  peter0lisa0simon0sarah0julie0
        ^
        |_This is where &names[2] points, i.e. this is where names[2] *is*

name是一个包含5个指针的数组,我用方括号和它的索引表示每个指针。另外,因为在我的机器上指针占4个字节,所以需要加一个空格。这是在names被初始化后的情况。右侧的单独内存块是一系列字节,在其中每个0表示一个0/NUL字节,而不是字符0。分配字符串文字的内存是实现(编译器、链接器和加载器共同工作)的责任 - 我假设你使用的所有字符串文字都将聚集在一起,尽管这并非必须如此。最后,数字0 ... 4表示names中每个指针指向的位置。

由于你正在分配一个char*,所以你需要一个char*。或者从另一个角度来看,如果指针本身具有相同的值,则指针指向相同的东西。因此,如果你想让search_names[i](它是一个指针)指向与names[i]指向相同的东西,那么search_names[i] = names[i]就是完全正确的。

但是,我不知道进行names[i]++的意图是什么。它修改了指针names[i]。修改指针会使其指向不同的东西。在这种情况下,你将得到names[0]指向"eter",names[1]指向"isa"等。

下面是在你递增names中的每个指针后内存的样子:

names                
|_____________           0     1    2     3     4
|             |          |     |    |     |     |
v             v          v     v    v     v     v
[0][1][2][3][4]         peter0lisa0simon0sarah0julie0

顺便说一下,你可以将字符串常量分配给char*,但这并不意味着你应该这样做。更好的做法是声明数组为const char *names[SIZE]。修改编译器为字符串常量分配的内存是未定义的行为,使用const char*而不是char*有助于强制执行。


2

names[]被定义为指向字符的指针数组。因此,names[i]是指向names中第i个字符串的指针。search_names[]也是指向字符的指针数组,因此,search_names[i]也是一个指针。因此,不需要对names[i]应用地址运算符,以使search_names[i]指向与names[i]相同的字符串。希望这能为您澄清事情。


1

所以你试图将数组名复制到search_names中?请注意,names和search_names都是指向字符的指针。例如,names [i]是一个指针。

表达式

search_names[i] = names[i]

将search_names[i]的值分配给names[i]。这只是将运行时堆栈上地址为&names[i]的内容放入地址为&search_names[i]的单元格中。在这种情况下,它只是复制一个指针。它不会复制字符。它只会复制来自单元格names[i]的内容——指向一系列字符的第一个字符的指针。

原因是

search_names[i] = names[i]++; 

等同于

search_names[i] = names[i]

在搜索名称的上下文中,这是因为增量运算符会影响names [i]的值。 它在赋值运算符之后具有较低的优先级。 因此,在赋值之后,表达式将增加names [i]。 由于names [i]是指针,所以增量会进行一些指针运算,这意味着它将指向地址(names [i] + sizeof(char))。

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