tags:

views:

199

answers:

7

I am speaking in Standard, K&R C.

Given:

const char a[] = {1, 2, 3};
const char *p = NULL;

Are these two statements equivalent:

  1. *p = a;

  2. p = a;

Each of them would be on the third line of the snippet.

1 and 2 certainly don't look the same.

What's the difference between the two then?

+4  A: 

No.

p = a initializes the pointer to point to something else (usually it copies another pointer or you will point to a reference, ala p = &a.

*p = a initializes what p refers to. You are "dereferencing" (looking at) what p points to. If p points to NULL as in your example, you will crash (this is good! you do not want to accidentally access something and mess your program up).

In this case, p = a will point to the first of the array a[], and *p = a will attempt to change the first of the array (it won't work; you have it declared const).

Here is a small example program in C++, with almost identical syntax to C.

#include <iostream>

int main()
{
    char arr[5] { 'a', 'b', 'c' }; // arr[3] and arr[4] are set to 0
    char *ptr = arr; //point to 'a'

    for (int i = 0; i != 5; i++)
    {
       *ptr = 'f'; //this changes the array
       ptr++; //this changes what the pointer points to; moves it to next in array
    }

    for (int i = 0; i != 5; i++)
    {
        std::cout << *ptr << " ";
    }

    //outputs f f f f f
}
Hooked
"and *p = a will attempt to change the first of the array (it won't work; you have it declared const)." Slight correction: p points to NULL; a has the array. He's dereferencing NULL, as you said in your 2nd paragraph; not changing the array, as you said in the third one.
Tordek
+1  A: 

The first dereferences a null pointer, and tries to assign it the address of the array. This will be a compiler error, because char != char []. If it weren't, it would likely crash.

The second sets p to point to the the array.

GMan
A: 

No, they are not equivalent

If p = NULL, then doing *p = a will give you a segmentation fault.

Casey
A: 
  1. Because "*p" dereferences the pointer wouldnt this make "p" a "char**" ?
  2. This would point "p" to the first array as expected.

I guess they are not the same.

Nippysaurus
+1  A: 

Here's a trick I used when I learned C (and still use today).

Whenever you see the * in front of a variable in your code, automatically read it as "what is pointed to by".

So you should be able to easily see that setting "p" to "a" is very different from setting "what is pointed to by p" to "a".

Also, since p is supposed to be pointing at a char, setting that char p is pointing at (currently the "char" at memory location 0 assuming null is 0) to a char pointer (a) is probably going to fail at compile time if you are lucky (depending on your compiler and lint settings it may actually succeed.)

from comment:In a function declaration like f(char c), I usually try to separate out the variable name from the rest of it--so it would be f( (char) c). so c is a char*. Exactly like a variable definition.

Also & usually reads as "The address of", but that gets even more iffy. A few examples of how I read things to myself. May or may not help you.

int a[] = {1,2,3}; // I mentally parse this as (int[]) a, so a is an int array.
int *p;            // p is a pointer to "integers"
int i;
p=a;               // p acts exactly as a does now. 

i=*p;          // i is "What is pointed to by" p (1)
i=p;           // i is some memory address
i=*a;          // i is what is pointed to by a (1)
i=p[1];        // Don't forget that * and [] syntax are generally interchangable.
i=a+1;         // Same as above (2).
p=&i;          // p is the address of i (it can because it's a pointer)
               // remember from hs algebra that = generally reads as "is", still works!
*p=7;          // what is pointed to by p (i) is 7;
a=*i;          // whoops, can't assign an array.  This is the only difference between
               // arrays and pointers that you will have to deal with often, so feel
               // free to use which ever one you are more comfortable with.

char c='a';
char *  d = &c;// d is a char pointer, and it is the address of c
char ** e ;    // e is a pointer to a memory location containing
               // a pointer to a char!
e=&d;          // gets d's address. a pointer to a pointer gets
               // the address of a pointer.  Messy but gets the job done

**e=5;         // what is pointed to by what is pointed to by e is 5.
*e=&'f';       // what is pointed to by e (which is a char * itself, and is still d!)
               // is set to the address of the memory location holding the value 'f'.
               // does not change c or e, just d!

I haven't touched c in 10 years, so some of this may be a bit wrong, but it helps me to read it out loud that way.

Bill K
What do you do when you see that in a function declaration?
Hooked
I would suggest extending the way you read * to declarations too, so that `int *p` reads as "what is pointed to by `p` is an `int`", rather than "`p` is an `int *`" which is a bit nebulous.
caf
+2  A: 

The * operator is what we call the dereference operator. To understand what it does, you must understand exactly what a pointer is.

When you do

char *p;

the "variable" p does not use the same amount of memory as a normal char, it uses more memory: it uses the amount of memory needed to correctly identify a memory position in your computer. So, let's say you use a 32-bit architecture, the variable p occupies 4 bytes (not the 1 byte you would expect from a char).

So, when you do

p = a;

you see clearly that you are changing the contents of the variable p, that is, you are putting another 32-bit number inside it: you are changing the address it is pointing to.

After that line executes, the value of p is the memory address of the character array a.

Now for the dereference operator. When you do

*p = 'Z';

you are telling the compiler that you want to store the value 'Z' ON THE ADDRESS pointed by p. So, the value of p remains the same after this line: it continues to point to the same address. It's the value of this address that has changed, and now contains 'Z'.

So, the final effect of

char a[] = {'a', 'b', 'c'};
char p = a;
*p = 'Z';

is the same as changing the first position of the array a to 'Z', that is:

char a[] = {'a', 'b', 'c'};
a[0] = 'Z';

NOTE: there is a difference when making a pointer point to an array: the variable that contains the array contains only the address of the first element, so a is the same as "the starting address of the array".

Usually you will see the & operator. It is an operator used to obtain the memory address of a variable. For example:

int number = 42;
int pointer = &number;
printf("%d", *pointer);

Here we have them all. The first line creates an integer variable and stores 42 inside it.

The second line creates a pointer to an integer, and stores the address of the variable number inside it.

The third line reades the value on the address pointed by the pointer.

So, the trick is to read *x as on the address pointed by x and &x as the address of x.

Bruno Reis
Hooked
+1  A: 

I think you are mistaking:

char a[8];
char *p=a;

which is legal and does the same as:

char a[8];
char *p=NULL;
p=a;

with:

char a[8];
char *p=NULL;
*p=a;

which as others said would generate a compile error or a segmentation fault.

 In the left side of declarations you should read *x as pointer(x) while in
 statements it must be read as value_pointed_by(x). &x on the other hand
 would be pointer_to(x)
jbcreix
caf
Yes it would be better like that, with it being regarded as a different type. However, C being as it is, it is better to declare char *p rather than char* p, as the former won't apply to subsequent variables which makes it counterintuitive. char* p,q; is char* p; char q; instead of char *p,*q; which is what you could be lead to believe.
jbcreix