-1

In my code I attempt to do the following things:

// Attempt #1
const char** strings;
strings[0] = "apple";
strings[1] = "orange";
strings[3] = "bananas";

// Attempt #2
const char* chars;
chars[0] = 'a'; // Error
chars[1] = 'b'; // Error again

When I compile GCC is fine with Attempt #1, but with Attempt #2 it says LHS must be assignable. Apparently by the virtue of const identifier the array chars is not assignable. Why?

Ace
  • 1,501
  • 4
  • 30
  • 49
  • Basically what you want is `const char* strings[N]` and `const char chars[N]` where `N` is the number of elements. Either that or you use `malloc` during runtime. In your second case you could do `const char chars[N] = { 'a', 'b' }` or just drop the `const`... – DeiDei May 24 '19 at 15:50
  • 1
    This would have been so much easier to understand had the standard *not* allowed prefix-const on the leading-most type (iow, mandate `const` be attached immediately after the type, not optionally before, but only for the outermost type). – WhozCraig May 24 '19 at 15:55
  • @DeiDei for the sake of consistency and uniformity (and perhaps the nature of code itself) I am against using array brackets. (Id rather do *(ptr +N) = value than ptr[N]) – Ace May 24 '19 at 15:58
  • 1
    @Ace You're going to get real-tired of doing that someday, and by real-tired, I mean tired of the coworkers maintaining your code asking you to decipher it because you're the only one on the team that does it. Just fair warning. – WhozCraig May 24 '19 at 16:08

2 Answers2

2

Read const char** as "a (non-const) pointer to a (non-const) pointer to a constant character". You're allowed to modify strings and strings[n], but not strings[n][m].

const char* is just one level in. You can modify chars but not chars[n].

The way you'd make strings[n] non-modifiable is with const char* const* - "a (non-const) pointer to a const pointer to a constant character"

Also note that in your example strings and chars are not initialized. You'll need to initialize them before you can actually access them.

This question has methods of how to read C declarations. In these simple cases you read right-to-left.

Kevin
  • 6,993
  • 1
  • 15
  • 24
  • Thank you that makes sense. So my intention is to make the array pointers in both cases immutable. I just want to change the values themselves that are contained in array[m] or perhaps array[n][m]. So then should we go for char* const chars; and char** const strings ? – Ace May 24 '19 at 15:55
  • Also I am not sure when you say the vars are not initialized. I believe that's exactly what I do right? – Ace May 24 '19 at 15:56
  • @Ace Neither are being initialized. You're performing *assignment*. Initialization doesn't just mean "set value". It is a language specific term, and means "establish value at the time of declaration". `int x; x = 5;` declares an uninitialized `int`, then assigned the value `5`. `int x = 5;` declares and initializes `x`. I.e. `x` does not exist without determinate value in the subsequent code. – WhozCraig May 24 '19 at 15:59
  • @WhozCraig Gotcha thx! These variables are tightly controlled within small inline functions. So chance of returning wild pointers (uninitialized) is rather small. But I take your point. – Ace May 24 '19 at 16:02
  • @Ace if you have `const char* chars;` you *must* assign `chars` to something (e.g. `chars = ...;` before you can do anything with `chars[0]` etc. – Kevin May 24 '19 at 16:02
  • @Kevin ^^ Yah understood! That is taken care of. These vars are first made to point to malloc'd space for N elements before doing any assignment. – Ace May 24 '19 at 16:04
  • @WhozCraig I see your point now. These pointers are made to point to malloc'd location first before mutating that space. I just havent shown it in the code for brevity. – Ace May 24 '19 at 16:06
1

char *string is a pointer to array of char's. something like this :

             .----.   .----.   .----.
             | s  | - | a  | - | m  |
             .----.   .----.   .----.
               ^
               |
char *string --.

it's just like you have an array and an pointer to the array :

char strArr[3];
char *ptrToStr = &strArr;

you can initialize an char * in various way :

char *string;
scanf("%as", string);
/* if you don't allocate buffer for `*string`, and specify "a" in string format, 
then `scanf` will do it for you. this is GNU-only extension. */

char *string2;
string2 = (char *) malloc (BUFF_SIZE);
sprintf(string2, "%s" , "Ghasem Ramezani");

...

But char **string is an pointer to pointer to char array. something like this :

                     .----.   .----.   .----.
                     | s  | - | a  | - | 1  |
                     .----.   .----.   .----.
                       ^
                       |
   .->  char *string --.
   |                 .----.   .----.   .----.
   |                 | s  | - | a  | - | 2  |
   |                 .----.   .----.   .----.
   |                   ^
   |                   |
   .-> char *string2 --.
   |
   .-------------.
                 |
char **strArr ---.

for example of char **, did you remember argv argument in main () ?. that's exactly is type of char **. let's see an example :

/*1*/ #include <stdio.h>
/*2*/ int main(int argc, char *argv[]) {
/*3*/   for (int i = 0; i < argc; ++i)
/*4*/     puts(argv[i]);
/*5*/   return 0;
/*6*/ }
$> gcc -o output main.c
$> ./output ghasem ramezani
./output
ghasem
ramezani
$>

as you can see in line 2, we can write char *[] instead of char **. why ? because as me and @Kevin said :

Read const char** as "a (non-const) pointer to a (non-const) pointer to a constant character".

Ghasem Ramezani
  • 2,683
  • 1
  • 13
  • 32