2

我有这个代码:


     char *name[] = { "a1", "b2", "c3", "d4" };
     printf("%s\n", *name); //the critical line

相关critical line

在这种形式中,输出很简单:a1. 如果我将其替换为critical line

printf("%s\n", ++*name);

那么输出是1. 我认为直到现在一切都很好。

考虑到name分别是指向第一个字符串的指针"a1",我将其替换为critical line

printf("%s\n", ++name);

希望我能得到"b2"结果作为输出。但我得到这个错误:

../src/test.c:32: error: lvalue required as increment operand.

问题:我不明白为什么++*name是合法的 -name是指向第一个字符串的指针 - 而++name不是。在我看来,++name应该移动name到下一个字符串。谁能解释一下我的理解不足在哪里?

4

4 回答 4

3

写入++name时,数组 name将转换为指向数组第一个元素的指针。此转换的结果不是左值,不能用++或以其他方式修改。您可以改为 write name+1,这将打印正确的内容。当name是一个数组时,无法修改它以引用除该数组[*] 之外的任何内容。

还要考虑:

char **p = name;   // OK, `name' converts to pointer
++p;               // OK, `p' is an lvalue
++(p+1);           // not OK, `p+1' is not an lvalue
++((char**)p);     // not OK, `(char**)p' is not an lvalue

++*name;           // OK, `*name' is an lvalue

粗略地说,“左值”是引用对象的表达式,而“非左值”是具有值的表达式。对象和值之间的区别在于,对象是存储值的地方(嗯,一次一个值)。值永远不能被修改,对象有时可以。

每当您有一个左值但需要其当前值的子表达式时,该对象就会被读取/加载/您想要调用它的任何内容。在 C++ 中,这被称为“左值到右值的转换”,我不记得它在 C 中是否被称为“评估子表达式”之外的任何东西。

name[*] 你可以在内部范围内使用另一个变量来隐藏它,它指的是别的东西。但这仍然没有修改外部name,只是暂时隐藏它。

于 2012-08-31T11:59:24.400 回答
2

name是一个数组,因此,除非您将其用作sizeofor&运算符的操作数,否则它会被评估为指向数组 objet 的初始成员的指针,而不是左值

因此,您不能name直接使用诸如++(请记住,后缀增量运算符需要可修改的左值作为操作数)的运算符进行修改。否则,您可以使用临时指针(p在以下示例中)。

#include <stdio.h>

const char *name[] = { "a1", "b2", "c3", "d4" };
const char **p = name;
printf("%s\n", *p); /* Output: a1 */
*++p; /* or *p++ */
printf("%s\n", *p); /* Output: b2 */
于 2012-08-31T11:53:09.260 回答
1

首先,确保您对以下事实完全满意和自信:数组不是指针。

其次,a里面有name什么?数组衰减为指向第一个元素的指针。衰减后,表达式name的类型为char **( 指向数组的第一个元素的指针char*。但是,衰减的表达式是rvalue。您不能修改它!自然如此,因为修改指向固定指针的指针是没有意义的大批。

因此,您不能直接增加作为衰减结果的指针,name只能说++5++foo() foo按值返回原始类型)[哎呀,这是对 C++ 的让步]

可以说的是:

char ** np = name;
++np;
printf("%s", *np);

这与 print 具有相同的效果name[1],但现在您还有一个变量,其中包含指向第二个数组元素的指针。

于 2012-08-31T11:59:53.527 回答
1

虽然 name 指向第一个元素的地址,但 name 不是type char *,而是char *[4]。所以,sizof(name) == sizeof(char *)*4

增加一个指针总是意味着增加它所指向的数据的大小。因此,在递增之后,它指向整个数组的后面。就像你有

    int i, a;
    int *p = &i;
    p++;

p 现在将指向i后面。如果编译器决定将 a 放在 i 后面,它将指向 a。

另请注意,您的数组仅包含 4 个指针,而不是 4 个字符串。像上面一样,这些字符串的实际位置是编译器的选择。因此,第一个字符串的结尾不一定紧挨第二个字符串的开头。特别是如果您稍后将其他值(字符串地址)分配给 name[1]。因此,您可以将 name 转换为char **,但不应转换为char *。增加前者将指向第二个元素(第二个 char* 指针)。

于 2012-08-31T12:15:09.003 回答