tags:

views:

345

answers:

9

I'm just starting out with pointers, and I'm slightly confused. I know & means the address of a variable and that * can be used in front of a pointer variable to get the value of the object that is pointed to by the pointer. But things work differently when you're working with arrays, strings or when you're calling functions with a pointer copy of a variable. It's difficult to see a pattern of logic inside all of this.

When should I use & and *?

+1  A: 

Ok, looks like your post got editted...

double foo[4];
double *bar_1 = &foo[0];

See how you can use the & to get the address of the beginning of the array structure? The following

Foo_1(double *bar, int size){ return bar[size-1]; }
Foo_2(double bar[], int size){ return bar[size-1]; }

will do the same thing.

wheaties
The question has been tagged C not C++.
Prasoon Saurav
And I've removed the offending cout <<
wheaties
+12  A: 

You have pointers and values:

int* p; // pointer to an integer
int i; // integer value

You turn a pointer into a value with *:

int i2 = *p; // integer value

You turn a value into a pointer with &:

int* p2 = &i; // pointer to an integer

Edit: In the case of arrays, they are treated very much like pointers. If you think of them as pointers, you'll be using * to get at the values inside of them as explained above, but there is also another, more common way using the [] operator:

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

To get the second element:

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

So the [] indexing operator is a special form of the * operator, and it works like this:

a[i] == *(a + i);  // these two statements are the same thing
Dan Olson
+1 for a very concise, beginner-friendly explanation
Kena
How come this doesn't work? `int aX[] = {3, 4}; int *bX = `
Pieter
Arrays are special and can be converted to pointers transparently. This highlights another way to get from a pointer to a value, I'll add it to the explanation above.
Dan Olson
If I understand this correctly... the example `int *bX =
Pieter
Dan Olson
caf
@Dan, given `int aX[] = {3,4};`, `int **bX = ` is an error. ``
Alok
Thanks Alok, that case is rare and always trips me up. :(
Dan Olson
A: 

Actually, you have it down pat, there's nothing more you need to know :-)

I would just add the following bits:

  • the two operations are opposite ends of the spectrum. & takes a variable and gives you the address, * takes an address and gives you the variable (or contents).
  • arrays "degrade" to pointers when you pass them to functions.
  • you can actually have multiple levels on indirection (char **p means that p is a pointer to a pointer to a char.

As to things working differently, not really:

  • arrays, as already mentioned, degrade to pointers (to the first element in the array) when passed to functions; they don't preserve size information.
  • there are no strings in C, just character arrays that, by convention, represent a string of characters terminated by a zero (\0) character.
  • When you pass the address of a variable to a function, you can de-reference the pointer to change the variable itself (normally variables are passed by value (except for arrays)).
paxdiablo
+3  A: 

I think you are a bit confused. You should read a good tutorial/book on pointers.

This tutorial is very good for starters(clearly explains what & and * are). And yeah don't forget to read the book Pointers in C by Kenneth Reek.

The difference between & and * is very clear.

Example:

#include <stdio.h>

int main(){
  int x, *p;

  p = &x;         /* initialise pointer(take the address of x) */
  *p = 0;         /* set x to zero */
  printf("x is %d\n", x);
  printf("*p is %d\n", *p);

  *p += 1;        /* increment what p points to i.e x */
  printf("x is %d\n", x);

  (*p)++;         /* increment what p points to i.e x */
  printf("x is %d\n", x);

  return 0;
}
Prasoon Saurav
+3  A: 

When you are declaring a pointer variable or function parameter, use the *:

int *x = NULL;
int *y = malloc(sizeof(int)), *z = NULL;
int* f(int *x) {
    ...
}

NB: each declared variable needs its own *.

When you want to take the address of a value, use &. When you want to read or write the value in a pointer, use *.

int a;
int *b;
b = f(&a);
a = *b;

a = *f(&a);

Arrays are usually just treated like pointers. When you declare an array parameter in a function, you can just as easily declare it is a pointer (it means the same thing). When you pass an array to a function, you are actually passing a pointer to the first element.

Function pointers are the only things that don't quite follow the rules. You can take the address of a function without using &, and you can call a function pointer without using *.

Jay Conrod
+2  A: 

There is a pattern when dealing with arrays and functions; it's just a little hard to see at first.

When dealing with arrays, it's useful to remember the following: when an array expression appears in most contexts, the type of the expression is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression appears as an operand of either the & or sizeof operators, or when it is a string literal being used as an initializer in a declaration.

Thus, when you call a function with an array expression as an argument, the function will receive a pointer, not an array:

int arr[10];
...
foo(arr);
...

void foo(int *arr) { ... }

This is why you don't use the & operator for arguments corresponding to "%s" in scanf():

char str[STRING_LENGTH];
...
scanf("%s", str);

Because of the implicit conversion, scanf() receives a char * value that points to the beginning of the str array. This holds true for any function called with an array expression as an argument (just about any of the str* functions, *scanf and *printf functions, etc.).

In practice, you will probably never call a function with an array expression using the & operator, as in:

int arr[N];
...
foo(&arr);

void foo(int (*p)[N]) {...}

Such code is not very common; you have to know the size of the array in the function declaration, and the function only works with pointers to arrays of specific sizes (a pointer to a 10-element array of T is a different type than a pointer to a 11-element array of T).

When an array expression appears as an operand to the & operator, the type of the resulting expression is "pointer to N-element array of T", or T (*)[N], which is different from an array of pointers (T *[N]) and a pointer to the base type (T *).

When dealing with functions and pointers, the rule to remember is: if you want to change the value of an argument and have it reflected in the calling code, you must pass a pointer to the thing you want to modify. Again, arrays throw a bit of a monkey wrench into the works, but we'll deal with the normal cases first.

Remember that C passes all function arguments by value; the formal parameter receives a copy of the value in the actual parameter, and any changes to the formal parameter are not reflected in the actual parameter. The common example is a swap function:

void swap(int x, int y) { int tmp = x; x = y; y = x; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);

You'll get the following output:

before swap: a = 1, b = 2
after swap: a = 1, b = 2

The formal parameters x and y are distinct objects from a and b, so changes to x and y are not reflected in a and b. Since we want to modify the values of a and b, we must pass pointers to them to the swap function:

void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);

Now your output will be

before swap: a = 1, b = 2
after swap: a = 2, b = 1

Note that, in the swap function, we don't change the values of x and y, but the values of what x and y point to. Writing to *x is different from writing to x; we're not updating the value in x itself, we get a location from x and update the value in that location.

This is equally true if we want to modify a pointer value; if we write

int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);

then we're modifying the value of the input parameter stream, not what stream points to, so changing stream has no effect on the value of in; in order for this to work, we must pass in a pointer to the pointer:

int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);

Again, arrays throw a bit of a monkey wrench into the works. When you pass an array expression to a function, what the function receives is a pointer. Because of how array subscripting is defined, you can use a subscript operator on a pointer the same way you can use it on an array:

int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}

Note that array objects may not be assigned; i.e., you can't do something like

int a[10], b[10];
...
a = b;

so you want to be careful when you're dealing with pointers to arrays; something like

void (int (*foo)[N])
{
  ...
  *foo = ...;
}

won't work.

John Bode
+1 for length of reply
Dave
A: 

Yeah that can be quite complicated since the * is used for many different purposes in C/C++.

When * appears in front of an already declared variable/function, it means that: a) * gives access to the value of that variable (if the type of that variable is a pointer type, or overloaded the * operator).
b) * has the meaning of the multiply operator, in that case, there has to be another variable to the left of the *

When * appears in a variable or function declaration it means that that variable is a pointer:

int int_value = 1;
int * int_ptr; //can point to another int variable
int   int_array1[10]; //can contain up to 10 int values, basically int_array1 is an pointer aswell which points to the first int of the array
//int   int_array2[]; //illegal, without initializer list..
int int_array3[] = {1,2,3,4,5};  // these two
int int_array4[5] = {1,2,3,4,5}; // are indentical

void func_takes_int_ptr1(int *int_ptr){} // these two are indentical
void func_takes int_ptr2(int int_ptr[]){}// and legal

when & appears in an variable or function declaration, it generally means that that variable is an reference to an variable of that type.

when & appears in front of an already declared variable, it returns the address of that variable

Additionally you should know, that when passing an array to a function, you will always have to pass the array size of that array aswell, except when the array is something like a 0-terminated cstring (char array).

smerlin
A: 
tommieb75
A: 

Just read Kernighan & Ritchie's book , it's one of the best books I have ever read. But it requires you to do the problems.

xxxxxxx