Pointers in C: when to use the ampersand and the asterisk? - Stack Overflow
arrays - What does ** do in C language? - Stack Overflow
I still don't understand the difference between "&" and "*" in C.
IN operator in C - Stack Overflow
You have pointers and values:
int* p; // variable p is pointer to integer type
int i; // integer value
You turn a pointer into a value with *:
int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to
You turn a value into a pointer with &:
int* p2 = &i; // pointer p2 will point to the integer i
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
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 = 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);
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.
In C, arguments are passed by values. For example if you have an integer varaible in main
int main( void )
{
int x = 10;
//...
and the following function
void f( int x )
{
x = 20;
printf( "x = %d\n", x );
}
then, if you call the function in main like this
f( x );
then the parameter gets the value of variable x in main. However the parameter itself occupies a different extent in memory than the argument. So any changes of the parameter in the function do not influence to the original variable in main because these changes occur in a different memory extent.
So how to change the varible in main in the function?
You need to pass a reference to the variable using pointers.
In this case the function declaration will look like
void f( int *px );
and the function definition will be
void f( int *px )
{
*px = 20;
printf( "*px = %d\n", *px );
}
In this case, the memory extent occupied by the original variable x is changed because, within the function, we get access to this extent using the pointer
*px = 20;
Naturally the function must be called in main like this
f( &x );
Take into account that the parameter itself that is the pointer px is a local variable of the function. That is, the function creates this variable and initializes it with the address of variable x.
Now let's assume that in main you declared a pointer for example the following way
int main( void )
{
int *px = malloc( sizeof( int ) );
//..
And the function is defined like
void f( int *px )
{
px = malloc( sizeof( int ) );
printf( "px = %p\n", px );
}
As parameter px is a local variable, assigning to it any value does not influence the original pointer. The function changes a different extent of memory than the extent occupied by the original pointer px in main.
How to change the original pointer in the function? Just pass it by reference!
For example
f( &px );
//...
void f( int **px )
{
*px = malloc( sizeof( int ) );
printf( "*px = %p\n", *px );
}
In this case, the value stored in the original pointer will be changed within the function because the function is using dereferencing, accessing the same memory extent where the original pointer was defined.
Q: what is this (**)?
A: Yes, it's exactly that. A pointer to a pointer.
Q: what use does it have?
A: It has a number of uses. Particularly in representing 2 dimensional data (images, etc). In the case of your example char** argv can be thought of as an array of an array of chars. In this case each char* points to the beginning of a string. You could actually declare this data yourself explicitly like so.
char* myStrings[] = {
"Hello",
"World"
};
char** argv = myStrings;
// argv[0] -> "Hello"
// argv[1] -> "World"
When you access a pointer like an array the number that you index it with and the size of the element itself are used to offset to the address of the next element in the array. You could also access all of your numbers like so, and in fact this is basically what C is doing. Keep in mind, the compiler knows how many bytes a type like int uses at compile time. So it knows how big each step should be to the next element.
*(numbers + 0) = 1, address 0x0061FF1C
*(numbers + 1) = 3, address 0x0061FF20
*(numbers + 2) = 4, address 0x0061FF24
*(numbers + 3) = 5, address 0x0061FF28
The * operator is called the dereference operator. It is used to retrieve the value from memory that is pointed to by a pointer. numbers is literally just a pointer to the first element in your array.
In the case of my example myStrings could look something like this assuming that a pointer/address is 4 bytes, meaning we are on a 32 bit machine.
myStrings = 0x0061FF14
// these are just 4 byte addresses
(myStrings + 0) -> 0x0061FF14 // 0 bytes from beginning of myStrings
(myStrings + 1) -> 0x0061FF18 // 4 bytes from beginning of myStrings
myStrings[0] -> 0x0061FF1C // de-references myStrings @ 0 returning the address that points to the beginning of 'Hello'
myStrings[1] -> 0x0061FF21 // de-references myStrings @ 1 returning the address that points to the beginning of 'World'
// The address of each letter is 1 char, or 1 byte apart
myStrings[0] + 0 -> 0x0061FF1C which means... *(myStrings[0] + 0) = 'H'
myStrings[0] + 1 -> 0x0061FF1D which means... *(myStrings[0] + 1) = 'e'
myStrings[0] + 2 -> 0x0061FF1E which means... *(myStrings[0] + 2) = 'l'
myStrings[0] + 3 -> 0x0061FF1F which means... *(myStrings[0] + 3) = 'l'
myStrings[0] + 4 -> 0x0061FF20 which means... *(myStrings[0] + 4) = 'o'
So I know roughly how pointers work. You have a value, say char x, and doing char* x isn't the actual content of the variable but rather the physical address it's located at.
But the thing that really confuses me is where we use "&" versus "*". I know "&" corresponds to the memory location of something, but isn't that what the pointer operator does? Just gives you the memory address of a variable? When exactly do we use "&" and "*"?
Is the pointer operator just for defining pointer "objects" (in a sense) while the ampersand is done as a way of reading a memory address versus operating with it?
There's no built-in C syntax that does this. You can write a function that does. Ie, if array[i] is an array of ints:
int in(int n, int* arr, int len) {
int i;
for (i = 0; i < len; ++i) {
if (arr[i] == n) {
return 1;
}
}
return 0;
}
In some contexts such a function might already exist in the standard library. As n.m pointed out, strchr finds a pointer to first occurence of a character in a character array, or else NULL, so you can do strchar(array[i], a) == NULL if array[i] is a character array.
No there's no in in C language.
If want, you can call a function passing the variable a to check if it is there in the array or not, using linear search(or binary depending on the data).
if(isKey(a,array)) // if(in(a,array))
{
}
int isKey(int a, int* array, int size)
{
// code to search element is present return 1 if present else 0
}
EDIT :- It was supposed to be a pointer mistake while . and edited for size.
I am currently working on an assignment in C where we are required to make a stack by simply using pointers.
I know the line: int *ptr = &val; declares ptr to be a "pointer to"(which is my interpretation of what asterisk * means in C) the "address of" the integer variable val.
When I want to create a double pointer, or a pointer to a pointer, I do so like:
int **ptr_ptr = &ptr; By setting ptr_ptr to a "pointer to" the address of pointer ptr.
When we use the asterisk anywhere other than in a declaration, it is usually referred to as dereferencing that pointer (I think), and grabbing the value that the pointer actually points to. This goes against my intuition that an asterisk means "pointer to".
Could anybody explain the proper meaning of the asterisk in C? Is it just that it means different things depending on how it is used (i.e. in a declaration versus anywhere else)?
Thanks!
* and & as type modifiers
int ideclares an int.int* pdeclares a pointer to an int.int& r = ideclares a reference to an int, and initializes it to refer toi.
C++ only. Note that references must be assigned at initialization, thereforeint& r;is not possible.
Similarly:
void foo(int i)declares a function taking an int (by value, i.e. as a copy).void foo(int* p)declares a function taking a pointer to an int.void foo(int& r)declares a function taking an int by reference. (C++ only)
* and & as operators
foo(i)callsfoo(int). The parameter is passed as a copy.foo(*p)dereferences the int pointerpand callsfoo(int)with the int pointed to byp.foo(&i)takes the address of the intiand callsfoo(int*)with that address.
(tl;dr) So in conclusion, depending on the context:
*can be either the dereference operator or part of the pointer declaration syntax.&can be either the address-of operator or (in C++) part of the reference declaration syntax.Note that
*may also be the multiplication operator, and&may also be the bitwise AND operator.
funct(int a)
Creates a copy of a
funct(int* a)
Takes a pointer to an int as input. But makes a copy of the pointer.
funct(int& a)
Takes an int, but by reference. a is now the exact same int that was given. Not a copy. Not a pointer.
Hi! Im trying to understand how the increment (++) and decrement (--) operators actually work in C, and the more I think about it, the more confused I get.
I understand the basic idea:
One version uses the old value first and then updates it.
The other version updates first and then uses the new value.
But I donโt get why this happens internally. How does the compiler decide the order? Does it treat them as two separate steps? Does this difference matter for performance?
Iโm also confused about this: C expressions are often described as being evaluated from right to left, so in my head the operators should behave differently if evaluation order goes that way. But the results donโt follow that simple โright-to-leftโ idea, which makes me feel like Iโm misunderstanding something fundamental.
Another thing I wonder is whether Iโm going too deep for my current level. Do beginners really need to understand this level of detail right now, or should I just keep learning and trust that these concepts will make more sense with time and experience?
Any simple explanation (especially about how the compiler handles these operators and how expression evaluation actually works) would really help. Thanks!
[] is called array subscript operator, but syntactically it's used on a pointer. An array is converted to a pointer to the first element in this usage (and many others). So, yes, [] is the same for arrays and pointers.
C11 ยง6.5.2.1 Array subscripting
Constraints
One of the expressions shall have type โโpointer to complete object typeโโ, the other expression shall have integer type, and the result has type โโtypeโโ.
Semantics
A postfix expression followed by an expression in square brackets
[]is a subscripted designation of an element of an array object. The definition of the subscript operator[]is thatE1[E2]is identical to(*((E1)+(E2))). Because of the conversion rules that apply to the binary+operator, ifE1is an array object (equivalently, a pointer to the initial element of an array object) andE2is an integer,E1[E2]designates theE2-th element ofE1(counting from zero).
Whether it does "one thing" depends on what you think "one thing" means.
In C, the operator is defined like so
e1[e2] means *(e1+e2)
That's it. One thing. Or is it? Suppose a is an array and i is an integer. We can write:
a[3]
a[i]
3[a]
i[a]
and suppose p is a pointer and i is an integer. We can write
p[3]
p[i]
3[p]
i[p]
Arrays or pointers. Two things? Not really. You know that when we use the plus operator where one of the two operands is "an array" you are really doing pointer arithmetic.
The second part of your question - can it be used for things other than pointer arithmetic - is basically no in C, but yes in C++, because in C++ we can overload this operator. However sometimes you will see [] in type expressions, but that is probably not what you are asking about because in that case, we aren't really using it as an operator (we're using it as a type operator, which is different).