0

I've taken the below code from one of the stack overflow posts: What does "dereferencing" a pointer mean?

Why does '''const char* q = p''' copy the pointer p to q such that when q is changed, p remains the same? it doesnt seem to make logical sense, const char* q should a store an address value of a char, it points to another pointer p. So instead, it points to an address, which stores another address, which is then the char

const char* p = asprintf("name: %s", name);  // Common but non-Standard printf-on-heap

// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
    if (!isprint(*q))
        *q = '_';

printf("%s\n", p); // Only q was modified
free(p);

Tried debugging to no avail

20MikeMike
  • 13
  • 4
  • `// Only q was modified`, not so. Also `*q` was modified (for several different values of `q`). Think about this, what is difference between `q` and `*q`? – hyde Nov 27 '22 at 13:04
  • im assuming, one is the address of q and the other is the value of q, the dereferenced value of q – 20MikeMike Nov 27 '22 at 13:11
  • No, value of `q` _is_ an address, and `*q` is accessing contents of that address AKA deteferencing a pointer. – hyde Nov 27 '22 at 13:12
  • *"rhe address of q"*, that would be `&q`, pointer to pointer, type `char**`. – hyde Nov 27 '22 at 13:13
  • 1
    Ohh q refers to the value at address of q? &q refers to address of q and *q refers to the chained rereferenced value of q? – 20MikeMike Nov 27 '22 at 13:17
  • Why should either `*q` or `*p` be modified? They are *both* defined as `const char`. – Adrian Mole Nov 27 '22 at 13:20
  • Okay given that, i think it makes sense now. q referring to the value at address q. const char* q = p then should refer to the value at address q being assigned the value at address p. Which the value at p is a pointer to a char, so q becomes the pointer to the char. But still, how is q unchanged when you increment it, and assign new values to its dereferenced values? – 20MikeMike Nov 27 '22 at 13:21
  • Try removing the `const` qualifiers. (Note that the line `*q = '_';` fails to compile with MSVC and clang-cl.) The C standard is less strict than C++ w.r.t. `const` but it still allows the compiler to put the variable(s) in read-only memory, IIRC. – Adrian Mole Nov 27 '22 at 13:24
  • Its been a while since i've done C, but it seems as though the author assigned pointer q to an address of const char, using another pointer p. He proceeds to increments the address of the pointer, dereference the addresses and assign new values. What should happen here? an exception being raised for changing the const char pointer q? – 20MikeMike Nov 27 '22 at 13:25
  • What *should* happen is that the compiler diagnoses your error. At the very least, a warning for the line I mentioned earlier. What compiler are you using? – Adrian Mole Nov 27 '22 at 13:31
  • But, the `const` issue notwithstanding, your `q` is initially assigned a ***copy*** of the address that `p` contains; that *copy* is modified in the loop, so the *original* value of the address (in `p`) remains unchanged. It's like if I have: `int a = 42; int b = a; ++b;` - that will change `b` from 42 to 43 but will leave `a` as it was first assigned. – Adrian Mole Nov 27 '22 at 13:35
  • Okay, but then he dereferences q and changes its value. While p is a constant char type, shouldnt this raise an exception>? – 20MikeMike Nov 27 '22 at 16:05

1 Answers1

0

A pointer is, in short, a type (or value of said type) representing the address of a value of another type.

So when writing char* p; It means that p is the address of a value of type char. Andp is of type char* (pointer to char).

When copying a value in C, both the origin value and its destination containers shall be of the same type. When doing

char* p = /* some address value*/;
char* q = p; 

What char* q = p; does is to copy the value of p (so, the address) into the variable q.

So for example, if p contains value 0x0110, q will contain value 0x0110 as well. An address is not much more than an unsigned integer, so here the copy works exactly the same.

It does not create a pointer to a pointer, but copies the address.

Now digging in the code you mentionned (which seems a bit strange to me, not sure we are able to modify a const value in this context, but that's not the important thing here.):

When needing more memory during execution of a program, in C we can manually ask the system for memory. This is called a memory allocation. An allocation returns a pointer to the allocated memory. It is done with functions like malloc or asprintf.

When we don't need the memory anymore, we have manually tell the system we don't need memory anymore, this is called releasing the memory. It is done with functions like free. Those fonctions usually take the pointer returned by an allocation as a parameter, so we have to keep track of it.

/* asfprintf does an allocation of a 
string (say S) in memory, and returns a 
pointer pointing to the "beginning" 
of the memory space allocated */
const char* p = asprintf("name: %s", name);  
    
    
/* here, we iterate over all characters of the string S,
pointed to by p
To do so, we have to compute the value of each 
successive character's address in the string, 
and we do this by incrementing the pointer p. 
However, we do it on a working copy of the pointer, 
to remember the value of the start of the memory chunk 
where S is stored
*/
for (const char* q = p; *q; ++q)
    if (!isprint(*q))
        *q = '_';
    
/*At this point, q has been incremented, 
and points to the last element of S, 
the terminating character, null-string.
Schematically, it looks like this
(0 is the string terminating character) : 
    
    name : the_na_me0
           |        |
           p        q

so here, when the comment below says "only q was modified", 
it means the address in p has not been changed, only the address 
in q has been incremented.
*/
printf("%s\n", p); // Only q was modified 
free(p); /*we can safely use p to release S's memory*/

I hope I have been clear, be sure to comment I you need clarification or more details.

Felix Bertoni
  • 400
  • 2
  • 10