Reputation: 1915
I am really getting confused on how pointers work. I am trying to write short little programs that will illuminate exactly how they work and I am having some troubles. For example:
char c[3]; //Creates an array of 3 bytes - the first 2 bytes can be used for characters and the 3rd would need to be used for the terminating zero
*c = 'a'; //sets c[0] to 'a'
*c++; //moves the pointer to c[1]
*c = 'b'; //sets c[1] to 'b'
*c++; //moves the pointer to c[2]
*c = '\0' //sets c[2] to the terminating zero
Obviously this code is not correct, or else I wouldn't be polling the forum :)
I am just having some troubles understanding this from a book, can anyone briefly explain the concept?
Upvotes: 3
Views: 866
Reputation: 21
Name of the array can be treated as the pointer to it's first element, though its a constant pointer hence it cannot be made to point to any other location. So c++
is not allowed.
Upvotes: 1
Reputation: 76650
First of all, c
here is not a pointer, it's an array. Arrays can in some contexts be used like pointers, but they are not the same thing. In particular, you can use *c
(as if it were a pointer) to access the value in the first position, but since c
is not really a pointer, you can't change where c
points by using c++
.
Second, you are misunderstanding what *
means. It's not just a decoration you use when using pointers. As an operator, it means "dereference", i.e. give me access to what is being pointed to. Therefore when you are manipulating the pointer itself (by, for example, incrementing it) and not manipulating the pointed-to data, you need not use it.
Here is what you probably wanted:
char c[3]; // Creates an array of 3 bytes - the first 2 bytes can be used for characters
// and the 3rd would need to be used for the terminating zero
char* p_c; // Creates a character pointer that we will use to refer into the c array
p_c = &c[0]; // Assign the address of the first element of the c array to the p_c pointer.
// This could also be "p_c = c", taking advantage of the fact that in this
// is one of the circumstances in which an array can be treated as if it were
// a pointer to its first element
*p_c = 'a'; //sets c[0] to 'a'
p_c++; //moves the pointer to c[1] (note no *)
*p_c = 'b'; //sets c[1] to 'b'
p_c++; //moves the pointer to c[2] (note no *)
*p_c = '\0' //sets c[2] to the terminating zero
Upvotes: 6
Reputation: 31186
Stepping through programs in a debugger and inspecting the values of everything was helpful to my understanding of pointers. Also draw lots of pictures on your whiteboard to solidify your understanding. The thing that really cemented it for me was learning assembly and bringing up a MIPS from scratch...
Try stepping through this in your debugger, and draw some diagrams on your whiteboard to trace out the execution.
#include <stdio.h>
int main()
{
char c_arr[3] = {'a', 'b', '\0'}; // Array of 3 chars.
char* c_ptr = c_arr; // Now c_ptr contains the address of c_arr.
// What does it mean that c_ptr "contains the address of c_arr"?
// Underneath all this talk of "pointers" and "arrays", it's all
// just numbers stored in memory or registers. So right now, c_ptr is
// just a number stored somewhere in your computer.
printf("%p\n", c_ptr);
// I got `0xbf94393d`. You'll get something different each time you run it.
// That number (0xbf94393d) is a particular memory location. If you
// want to use the contents of that memory location, you use the *
// operator.
char ch = *c_ptr;
// Now ch holds the contents of whatever was in memory location 0xbf94393d.
// You can print it.
printf("%c\n", ch);
// You should see `a`.
// Let's say you want to work with the next memory location. Since
// the pointer is just a number, you can increment it with the ++ operator.
c_ptr++;
// Let's print it to see what it contains.
printf("%p\n", c_ptr);
// I got 0xbf94393e. No surprises here, it's just a number -- the
// next memory location after what was printed above.
// Again, if we want to work with the value we can use the *
// operator. You can put this on the left side of an assignment
// to modify the memory location.
*c_ptr = 'z';
// Since c_ptr was pointing to the middle of our array when we
// performed that assignment, we can inspect the array to see
// the change.
printf("%c\n", c_arr[1]);
// Again, c_ptr is just a number, so we can point it back to
// where it was. You could use -- for this, but I'll show -=.
c_ptr -= 1;
// We can also move by more than one. This will make the pointer
// contain the address of the last memory location in the array.
c_ptr = c_ptr + 2;
return 0;
}
Here's my attempt at a picture. This box is your computer's memory. Each location in memory is assigned a number, we call that number an address.
++++++++++++++++++++++++++++++++++++++++++++
| NAME | ADDRESS | VALUE |
+=========+==============+=================+
| c_arr | 0xbf94393d | 'a' |
| | 0xbf94393e | 'b' |
| | 0xbf94393f | '\0' |
+---------+--------------+-----------------+
| c_ptr + <someaddr> | 0xbf94393d |
+------------------------------------------+
When you access, say, c_arr[0]
, you are working with the top row in the table. Note that c_ptr
has as its value the address of the top row in the table. When you say *c_ptr
, you are telling the CPU to use 0xbf94393d
as the address to operate on. So *c_ptr = 'z'
is a bit like saying "Hey, go to 0xbf94393d and leave a 'z' there" -- on this street the addresses are really big.
Upvotes: 1
Reputation: 18010
Pointers and arrays are different things in C. The source of confusion is that arrays get converted (decay, as the Standard names it) to pointers at the slightest provocation. It's called "decay" because it loses some information about array type (namely, its size).
Let's see...
void f( char* p );
char c_array [3]; // define an array
char *c_ptr = c_array; // define a pointer and set it to point at the beginning of the array
// here array "decays" to pointer
*c_ptr = '1';
assert(c_array[0] == '1');
assert(c_ptr[0] == '1'); // this works too... in fact, operator [] is defined
// for pointers, not arrays, so in the line above array
// decays to pointer too.
++c_ptr; // move the pointer
//++c_array; // -- this won't compile, you can't move the array
*c_ptr++ = '2';
*c_ptr = '\0';
assert(c_array[1] == '2');
assert(c_array[2] == 0);
assert(sizeof(c_array) == 3); // no decay here!
assert(sizeof(c_ptr) == sizeof(void*)); // a pointer is just a pointer
f(c_array); // array-to-pointer decay, again
// now, what happens here?
void g( char param [100] )
{
++param; // it works!
// you can't pass an array as a parameter by value.
// The size in the parameter declaration is ignored; it's just a comment.
// param is a pointer.
assert(sizeof(param) == sizeof(void*));
// yes, it's just a pointer
assert(*param == '2'); // in the call below
}
g(c_array); // array-to-pointer decay, again
Hope this helps a bit.
(Note that I've intermingled declarations and statements for the purpose of illustration. You'll have to rearrange things a bit to make it a valid C program).
EDIT: added sizeof examples
Upvotes: 3
Reputation: 791531
c
is not a pointer, it's an array. Although the name of an array decays to a pointer in most array contexts you can't treat an array name as a modifiable pointer. The result of the decay is just a temporary (technically an rvalue).
For this reason you can't apply ++
to the name of an array. If you want increment a pointer, use a pointer:
char *d = c;
Upvotes: 15
Reputation: 1239
Try
c++;
*c = 'b';
c++;
*c = '\0';
The * operator is trying to dereference the pointer. All you need to do is move the pointer, then do your assignment.
Upvotes: 0