1

I've just read this that by pointing a pointer to the first array member, you can cycle through by adding to the pointer.

char my_array[] = "I am an array of chars";

char *my_pointer = my_array;

printf("%c\n", *my_pointer);

my_pointer++;

printf("%c", *my_pointer);

I guess this implies array members are always stored sequentially, and the space allocated is always reserved and an array's size can not be extended (because after the length it may contain other things in memory)?

Why does this work exactly? When accessing an array using a subscript, like my_array[5], will C only know where the array starts (i.e. my_array[0]), and have to increase an internal pointer by 5 to return it?

I apologize if this seems obvious, but I've spent my life in high level languages and C is very interesting to me.

alex
  • 479,566
  • 201
  • 878
  • 984

5 Answers5

7

Putting aside the problems with your code, yes, arrays are contiguous elements.

What happens with the second line of the code snippet below:

int * iptr = malloc (40 * sizeof(int));
int x = iptr[10];

is thus:

  • the value 10 is multiplied by the size of the int to get 70 (in this example, we assume a 7-byte int).
  • this is then added to the base pointer iptr (unscaled) and the (7-byte) value is extracted from that location.

This scaling is an important feature. You won't see it when you're working with char arrays but the values &(iptr[0]) and &(iptr[1]) will be separated by the size of an int, not a char (7 in our example case above).

When you add 1 to a pointer, that doesn't actually add 1, it adds the size of the underlying data type. So that:

int *p = &(iptr[0]);
p++;

won't give you an address corresponding to the second byte of that memory, it will actually give you the address of the second int (the seventh byte).

To that end, iptr[3] is exactly equivalent to *(i+3) in that they both give you element number three, even though it's made up of bytes from offset 21 through 27 inclusive.


Pre-emptive strike, just in case: keep in mind that a byte in ISO C is not necessarily 8 bits. ISO uses the term octet for that. A byte is the size of a char.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 2
    `%p` requires the pointer to be cast to `(void *)` (the usual implicit conversion doesn't happen because it's part of the variable argument list). – caf Sep 06 '10 at 06:02
  • I am pretty sure that arrays are allocated contiguously. If they weren't, then [] wouldn't work. – Alexander Rafferty Sep 06 '10 at 06:18
  • Actually you're right, @Alex. I envisaged a scenario where element could be stored at only even physical addresses (leaving odd ones blank) and the C compiler would automatically skip odd ones when doing its calculations. That would work, but I was trying to be too clever by half :-) C99 specifically states "An array type describes a contiguously allocated ..." so, regardless of what would happen at the hardware level, the C "machine" only knows about its own level. Fixed. – paxdiablo Sep 06 '10 at 06:24
2

This nice answer might help

Community
  • 1
  • 1
1

Your code has some bugs in it. Here is a working example.

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
  char my_array[] = "I am an array of chars";
  char* my_pointer = &my_array[0];

  int len = strlen(my_array);
  int i;
  for (i = 0; i < len; ++i) {
    printf("%c\n", *my_pointer);
    ++my_pointer;
  }

  return 0;
}

Like @RC's link points out, incrementing a pointer will walk the contiguous block of memory that is a C array.

If you change this line

char* my_pointer = &my_array[0];

to this

int* my_pointer = &my_array[0];

then not only will you get a compile warning, but you will get all kinds of gobbley-gook printed out as it will walk past the end of your array and print out whatever is in memory. Your pointer datatype should match your array if you want to walk over it properly.

Hitesh
  • 1,413
  • 1
  • 11
  • 11
0

I'm sorry, but there are a few mistakes in your example provided.

You need to declare my_array as

char my_array[] = "string...";

and get rid of either the & or the [0] in the second line (both have same effect).

you need to change the * in the 3rd and 5th lines to a & or a [0] (again, same effect).

The reason that this happens is because a string (array of char's) is a series of chars in memory. The char* points to the first one, so incrementing it will make it point to the second, third, ect...

You could increment it past the end of the string to see what else is stored in your app's memory (but this could crash your program).

-Alex

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55
  • 3
    & takes the adress, [0] dereferences the first character. You should get rid of both or keep both. The second expresses that you take an address. – harper Sep 06 '10 at 05:15
  • oh of course, I'm getting my operators mixed up (damn those pointers). The expression &array[0] is exactly the same as array, and so is useless. – Alexander Rafferty Sep 06 '10 at 05:24
  • `&arr` and `arr` [are different](http://publications.gbdirect.co.uk/c_book/chapter5/arrays_and_address_of.html): "the address of the first element has type ‘pointer to T’; the address of the whole array has type ‘pointer to array of n elements of type T’" – detly Sep 06 '10 at 06:03
  • No it's not - `sizeof array` and `sizeof &array[0]` may well produce a different answer... – caf Sep 06 '10 at 06:04
  • Although I may have misunderstood your comment there @Alexander Rafferty – detly Sep 06 '10 at 06:05
  • In practice, [0] and & are the same thing. The address of an array is the address of it's first element. – Alexander Rafferty Sep 06 '10 at 06:15
  • Same numeric address != same type. ``int *ip` for `arr` or `&arr[0]` vs `int (*ar10i)[10]` for `&arr`. Although I think we're now arguing at cross purposes, because you never mention `&arr`, just the other two. – detly Sep 06 '10 at 06:27
  • Thanks, I have tried to update the code in the question to be correct. – alex Sep 06 '10 at 06:28
0

my_pointer point to a string in memory. Each CHAR is 1 byte. So my_pointer++ will look at the next byte and hence the next character. The read my_pointer++ as a string it will continue through memory until it finds null as all strings should be null terminated.

fyi

my_pointer += sizeof(type_of_array) will go to the next item in the array so long as you cast the pointer correctly.

malloc can be used to manage the memory available to your program. This takes care of finding free memory space to allocate the object to.

Matt
  • 873
  • 1
  • 9
  • 24
  • no, my_pointer++ will increment the pointer by the size of data type. This is a handy feature of C++, as it allows us to forget about the size of the data type an array is pointing to. So, if float* a = (float*)1000; (hypothetically) then a++; would make a=1004; – Alexander Rafferty Sep 06 '10 at 06:17
  • Um the OP posted about C not C++. – Matt Sep 06 '10 at 07:50