首先,我目前正在使用
Microsoft Visual Studio Community 2022 (64-bit) - Current Version 17.7.5
。 (以防万一这个问题更多的是关于我正在使用的工具而不是语言,当我建议这是关于 c 语言本身时我错了。)
下面的情况 1 给出了此错误:
expression must be a modifiable lvalue
/* case 1 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* defaultlist[] = { "string 1", "string 2" };
char** getlist() { return NULL; }
int main( int argc, char* argv[] ) {
char* list[]= getlist(); /* line with declaration I'm accustomed to using in past */
if ( list == NULL )
list = defaultlist; /* line with error message */
return 0;
}
情况2没问题:
/* case 2 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* defaultlist[] = { "string 1", "string 2" };
char** getlist() { return NULL; }
int main( int argc, char* argv[] ) {
char** list= getlist(); /* modified declaration */
if ( list == NULL )
list = defaultlist; /* no error, anymore */
return 0;
}
在我古老的过去,“
char** p
”和“char* p[]
”的声明之间没有任何语义差异。在 1970 年代、1980 年代和 1990 年代,当我花在 c 上的时间比最近多时,它们在所有声明上下文中都具有相同的语义。 (如果我错了,我希望得到严厉的纠正并举一个例子来说明差异。)
我现在观察到来自编译器的抱怨,它提出了我以前不习惯的新语义。看来现在,c编译器已经决定
char* list[]
真的是char* (* const list)
。这不是我的本意。
应注意以下几点:
char** p
和 char* p[]
的声明语义在某些时候是相同的?如果是这样,并且如果即使回到 1978 年我第一次学习 C 语言来处理 Unix v6 内核代码时它也一直是不同的,那么它究竟有何不同以及如果我尝试这样做的话我如何检测到差异? (我这里有很多旧的编译器,可以用于测试目的。)char** p
和 char* p[]
的声明语义现在有所不同,因为 char* p[]
在我尚未了解的某些情况下实际上被视为 char* (* const p)
并且这c 标准的某些修订发生了变化吗? (或者我错过了考虑的其他语义?)在我古老的过去,两者之间没有任何语义差异 一个声明为 char** p,另一个声明为 char* p[]。他们有 在 20 世纪 70 年代、1980 年代的所有声明上下文中具有相同的语义, 1990 年代我花在 c 上的时间比最近更多
这从来都不是事实。区别从C语言开始都是一样的。
char **p;
声明一个指向 char 的指针。char* defaultlist[] = { "string 1", "string 2" };
定义了两个指向char的指针的数组。数组无法赋值(即用作左值),指针可以。
这两行都不会编译:
char* list[]= getlist();
list = defaultlist;
您的困惑是初学者对数组和指针的普遍误解。
当用作右值时,数组会衰减为指针,但它们不是指针。