First off, I'm currently using Microsoft Visual Studio Community 2022 (64-bit) - Current Version 17.7.5
. (Just in case this question is more about the tools I'm using than the language and I'm mistaken when suggesting this is about the c language itself.)
Case 1 below gives this error: 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;
}
Case 2 is fine:
/* 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;
}
In my ancient past there was no semantic difference whatsoever between a declaration that says char** p
and one that says char* p[]
. They had identical semantics in all declaration contexts in the 1970's, 1980's, and 1990's when I spent more time with c, than of late. (If I'm wrong about that, I'd like a stern correction and an example demonstrating the difference.)
I'm now observing a complaint from the compiler that suggests a new semantics I've not been accustomed to, previously. It seems that now, c compilers have decided that char* list[]
is really char* (* const list)
. Which isn't my intention.
The following points should be addressed:
char** p
and char* p[]
were at some point identical? If so, and if it has always been different even back to the 1978 when I first learned C working on the Unix v6 kernel code, then exactly how has it been different and how might I have detected the difference had I tried to do so? (I have many old compilers here that I can use for testing purposes.)char** p
and char* p[]
are now different in the sense that char* p[]
, in certain circumstances I've yet to learn about, are actually taken as char* (* const p)
and that this change occurred in some revision to the c standard? (Or some other semantic meaning I missed considering?)In my ancient past there was no semantic difference whatsoever between a declaration that says char** p and one that says char* p[]. They had identical semantics in all declaration contexts in the 1970's, 1980's, and 1990's when I spent more time with c, than of late
It was never the truth. The difference is the same from the beginning of the C language.
char **p;
declares a pointer to pointer to char.char* defaultlist[] = { "string 1", "string 2" };
defines the array of two pointers to char
.Arrays can't be assigned (ie used as lvalues), pointers can.
Both lines will not compile:
char* list[]= getlist();
list = defaultlist;
Your confusion is a widespread beginner's misunderstanding of arrays and pointers.
Arrays decay to pointers when used in as rvalues, but they are not pointers. Same happens when you pass the array to a function - you actually pass the pointer to the first element of the array). The confusion comes from the way you can declare function parameters:
void foo(int arr[], int *arr1[]);
They look like arrays but they are pointers.
When was the change made, assuming I am right that a change was made in the standard?
It was always like this. Arrays and pointers were always not the same
char* p[], in certain circumstances I've yet to learn about, are actually taken as char* (* const p)
No, you are 100% wrong. You cant assign arrays, but not because they are const
Am I mistaken in asserting the declaration semantics of char** p and char* p[] were at some point identical?
No, they were never the same.
You are probably confused by this ancient way of declaring parameters:
void foo(p)
int p[];
{
int arr[5];
p = arr;
}
It looks like you assign array p
, but p
(because it is a parameter) is a pointer despite the confusing syntax.