I have a pointers in C, and I can't figure out how it works.
Below is the code:
// ptr points to an array of 2 ints
int (*ptr)[2];
int torf[2][2] = {12, 14, 16};
ptr = torf;
int (*ptr_2)[2];
int torf_2[2][2] = { {12}, {14, 16}};
ptr_2 = torf_2;
printf("%d %d\n", **ptr, **(ptr + 2));
printf("%d %d\n", **ptr_2, **(ptr_2 + 2));
The answer I want should be:
12 16
12 14
But actually I got on my PC:
12 6422000
12 12
Any ideas?
try this:
// ptr points to an array of 2 ints
int(*ptr)[2];
int torf[2][2] = { 12, 14, 16 };
ptr = torf;
int(*ptr_2)[2];
int torf_2[2][2] = { {12}, {14, 16} };
ptr_2 = torf_2;
printf("%d %d\n", **ptr, **(ptr + 1));
printf("%d %d\n", **ptr_2, **(ptr_2+1));
when you use pointers it is like the indexes of the array it begin from 0;
good work
If you add these lines to the end of your program:
printf("%p: %p %p\n", ptr, ptr+1, ptr+2);
printf("%p: %p %p\n", *ptr, *ptr+1, *ptr+2);
printf("%p: %p %p\n", **ptr, **ptr+1, **ptr+2);
You will note that in the first case, the numbers increase by 8, which could either be the size of a pointer or two ints. Same goes for the second, but the third increases by the size of an int; so that is good.
So, to disambiguate 2 ints or 1 address, lets do a s/2/3/g.
Now, we see the first case the increment is now 12 ( = 3 * 4 ).
Your second case ( *ptr + i ) increments by 4, so is the address of successive ints
Your third case is the integer values themselves.
Where did it get confusing? Quick checklist:
When you are trying to workout pointer / indexing problems, use unique values as much as possible.
Pay attention when the compiler warns you. Eventually you will know to ignore "format '%p' expects argument ... ", but it takes time to build the confidence.
There is a handy program, cdecl, which converts C type expressions into something english like.
In virtually all C implementations, int x[2][2], y[4]; have the same layout; that is, C multi-dimensional arrays are just an overlay of a single dimension array, with the arithmetic cleverly hidden. For this reason, definitions like int (*p)[2]; are rare and rarely useful.
If you must go down this road, it is likely better to do something like:
typedef int pair[2];
pair torf[2] = { { 0, 1 }, { 2, 3 }};
pair *ptr = torf;
if nothing else, somebody has a chance to understand it...
Related
I'm playing with OnlineGDB compiler in order to understand how pointers work in C.
First, I ran the following code and got the output I expected:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0+1]);
printf("%d", array1[1+1]);
return 0;
}
Output was:
4
3
Secondly, I ran the following code - And I can't understand its output:
int *array1[] = {1,4,3,4};
int main()
{
printf("%d \n", array1[0]+1);
printf("%d", array1[1]+1);
return 0;
}
Output:
5
8
It seems like I'm adding 4 to the value from the array, but why? (each element in the array is consisted from a byte).
Thanks!
It seems like I'm adding 4 to the value from the array, but why?
No, each element of the array is an int * because you declared the array that way:
int *array1[] = {1,4,3,4};
That says array1 is an array whose values have type pointer to int. Remove the * if you want an array of int, like:
int array1[] = {1,4,3,4};
When you add or subtract from pointer types, the value changes by some multiple of the size of the type that the pointer refers to. An int on your system is probably 4 bytes, so an expression like array1[0]+1 gets the int * stored in array[0] and increments it, so it increases by sizeof(int).
(each element in the array is consisted from a byte).
Even if you had declared your array as an array of int rather than an array of int *, the size of an int is probably not 1 byte. int is typically 4 bytes long, but size depends on the compiler and target system.
With
int *array1[] = {1,4,3,4};
you are defining tan array of pointers to integers.
So every element of that array, even if initialized with what appear to be integer values, are actually pointers, that are addresses.
If you had deferenced those pointers you would probably have caused a segmentation fault. But fortunately you simply printed them, even if using %d instead of %p: a choice that according to C standard could have caused undefined behavior. Anyway in your case the pointers were converted to integers, and the printed values were the expected ones. Exactly like if the array was an array of integers.
In the second example you pushed it further: you added 1 to the array elements. But since they are pointers, then pointers arithmetics is applied. Meaning that pointer + N = pointer + N * sizeof(*pointer). In this case, since sizeof(int) is 4:
array[0] + 1 =
= 1 + sizeof (array[0]) =
= 1 + sizeof( int ) =
= 1 + 4 = 5
int main(void) {
int* b[3] = {1, 2, 3}; // b is an array of pointers to integer
printf("%d", b); // b = address of array of pointers
printf("\n%d", *b); // *b should be address of the place where 1 is stored ....right?
printf("\n%d", *(b+1)); // similarly *(b+1) should be address of place where 2 is stored
printf("\n%d", *(b+2)); // and so on... But they print 1,2 and 3
printf("\n%d", b[0]); // prints 1 . No problem!
printf("%d", *(*(b+1)+2)); // Also why does this give segmentation fault?
//PLUS I GET THIS WARNING : array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
//PLEASE EXPLAIN !! I think I have misunderstood something.
return 0;
}
Below I have attatched a sketch of how I think they are stored. Please correct me with a better sketch if I am wrong.
Your code has many problems, mostly coming from the fact that int *b[3] does not have a proper initializer. { 1, 2, 3 } is OK for an array of int, not for an array of int *, as the compiler correctly diagnoses:
array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
For compatibility with ancient code, the compiler only issues a warning, but such warnings indicate errors that must be corrected. I strongly suggest you compile your code with -Wall -Werror to let the compiler produce errors instead of mere warnings for such problems.
Accessing adresses 1, 2 or 3 most likely has undefined behavior, which takes the form of a segmentation fault on your system.
To initialize the array of pointers, you can specify the addresses of int variables.
Here is a corrected version:
#include <stdio.h>
int main(void) {
int x = 1, y = 2, z = 3;
int *b[3] = { &x, &y, &z }; // b is an array of pointers to integer
printf(" b: %p\n", (void*)(b)); // b = address of array of pointers
printf(" *b: %p\n", (void*)(*b)); // *b is the address of variable x that has a value of 1
printf(" *(b+1): %p\n", (void*)(*(b+1))); // similarly *(b+1) is the address of y where 2 is stored
printf(" *(b+2): %p\n", (void*)(*(b+2))); // and so on...
printf(" *b[0]: %d\n", *b[0]); // prints 1. No problem!
printf("*(*(b+1)): %d\n", *(*(b+1))); // prints 2
// accessing *(*(b+1)+2) would have undefined behavior because b[1] is
// not the address of an array of at least 3 ints.
printf(" b[2][0]: %d\n", b[2][0]); // prints 3
return 0;
}
Note that pointers cannot be printed with %d as it has undefined behavior because pointers may be passed differently from integers to printf. The format is %p and the pointer should be cast as (void*) for complete portability.
Arrays are stored consecutively in the address space.
Their allocation is static, meaning you don't allocate space for it at run time and as a result of this, they are stored in different memory region - stack.
An array determines its size by the amount of elements multiplied by the size of the data type, (because you have packed a variable n-times).
The size is the space in bytes it occupies in the memory. It should not be confused with the length of the array, which is how many elements are in the array. For example int arr[2] is usually 8 bytes (sizeof(int[2])) but is an array with the length of 2.
There are many ways to initialize array, but two ways to de-reference it.
One is by using the index operators [] and the other is to de-reference the pointer it decays to with * Example:
int arr[3];
arr[0] = 40;
*arr = 40;
arr[2] = 40; // <-- this is functionally equivalent to..
*(arr + 2) = 40; // <--this (Note the pointer arithmetic involved)
int* arr[3] - This is an array of int pointers.
The index operator has very high precedence, higher than *
To get around that, and substantially create a pointer to an array of 3 elements, you use the brackets to define the priority of evaluation:
int (*arr)[3];
Bracket's second use-case is to make a "derived type" - a function. ([], *, () are used to define a derived type)
How to initialize them at declaration time?
An array of characters
char arr[3] = {'a', 'b', 'c'}
char arr[] = {'a', 'b', 'c'}
char arr[3] = "hi" // Note this is a string, not array of characters anymore
To initialize the first element of an array of int pointers you can very well do this:
char ch1 = 'a';
char* arr[3] = { &ch1 };
And finally, initialize a pointer to an array of 3 characters:
char arr[3] = {'a', 'b', 'c'};
char (*arr2)[3] = arr;
int* b[3] = {1, 2, 3};
This is stored like this:
b
+-----+
| 1 |
+-----+
| 2 |
+-----+
| 3 |
+-----+
You asked for an array containing 1, 2, and 3, and you got an array containing 1, 2 and 3. It does not create separate variables containing 1, 2 and 3 and then put pointers to those variables in the array. No, it just puts 1, 2 and 3 in the array and carries on.
The warning is because it is very uncommon and usually wrong to be writing a memory address directly. What's at memory address 1? Damned if I know. Probably it's not even a valid address, so when you do *b[0] it just crashes.
*b is the same as b[0], *(b+1) is the same as b[1] and so on. So those are just fetching the "pointers" in the array - not the things they point to.
*(*(b+1)+2) segfaults because it's accessing address 10 (on a 32-bit system). Probably 10 isn't a valid address of anything either. So you get a segfault.
I am creating a two-dimensional array in C as follows:
int array1[] = {1,2,3,4,5,6,7,8,9,10};
int array2[] = {11,12,13,14,15};
int* array3[2] = {array1,array2};
and now I want to get the size of both dimensions. For the first dimension I get the correct result of 2 if I use the following code:
int array3_x = sizeof(array3)/sizeof(*array3); // array3_x = 2
but I am not able to get the size of the other dimension. So far I have tried the following:
for (int i = 0; i < array3_x; ++i) {
array3_y[i] = sizeof(array3[i])/sizeof(*array3[i]);
}
I always get a result of 1. Is there a way to get the correct sizes of 10 and 5?
There is this idea of arrays being pointers. They're not. Arrays can degenerate into pointers. The idea here is that arrays are stored contiguous in memory, so if we have a pointer to the first element, we can use pointer arithmetics to get the rest. But understand that this is a pointer to the first element, not an array.
By typing int* array3[2] = {array1,array2};, you create an array that consists of two pointer to first elements of arrays. Those pointers do not carry any information about the length of the arrays. Ever seen a function that takes such a pointer as argument? Those tend to also get the size as another argument. (except for the null-terminated arrays of char)
As a result, you have to store the information in some other way. Being used to C++, my approach would be to use a structure that imitates a class. Essentially imitating the C++ std::vector. That said, I'm not that used to C, no idea if this is the standard approach here.
Edit: An important thing here is your application. The best approach of course needs to know what you want to do. If for example you'd want to store 2D grid data, I'd simply go with a 1D array of size n*m. If you want to store jagged data, you could simply accompany it with an array that stores the sub-arrays sizes.
Perhaps this might work:
If you can turn the arrays into zero-terminated arrays:
int array1[] = {1,2,3,4,5,6,7,8,9,10,0};
int array2[] = {11,12,13,14,15,0};
int* array3[2] = {array1,array2};
Then you can use a function like this to get the length of each:
/********************************************************************
** Get the length of a zero-terminated int array.
*/
size_t LengthOfIntArray(int *array)
{
int *index = array;
while(*index)
++index;
return((size_t)(index - array));
}
And you can print the length of each array like this:
/********************************************************************
** Program start
*/
int main(void)
{
int i;
int array3_x = sizeof(array3)/sizeof(*array3); // array3_x = 2
printf("Height of array3: %d\n", array3_x);
for(i = 0; i < array3_x; ++i)
printf("Length of array3[%d]: %zd\n", i, LengthOfIntArray(array3[i]));
return(0);
}
The output will be:
Height of array3: 2
Length of array3[0]: 10
Length of array3[1]: 5
#include <stdio.h>
#include <stdlib.h>
int main() {
int array1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int array2[] = {10, 11, 12, 13, 14};
int *array3[] = {array1, array2};
unsigned long int c1, c2, c3;
c1 = sizeof(array1) / sizeof(*array1);
c2 = sizeof(array2) / sizeof(*array2);
c3 = sizeof(array3) / sizeof(*array3);
printf("size of array1 : %2lu\n", c1);
printf("size of array2 : %2lu\n", c2);
printf("size of array3 : %2lu\n", c3);
/* so far, so good ...
however, the following "printf"s will fail
to give assumed results
*/
c1 = sizeof(array3[0]) / sizeof(*array3[0]);
c2 = sizeof(array3[1]) / sizeof(*array3[1]);
printf("size of array1 : %2lu\n", c1);
printf("size of array2 : %2lu\n", c2);
return 0;
}
In your code, on line array3_y[i] = sizeof(array3[i])/sizeof(*array3[i]); in the for loop, array3[i] does no more point to an array --the compiler has no information about the length of the variable that it's pointing at, whether it is an array, a single char or an int or something else-- but it is just a plain pointer (presumably a pointer pointing to a default int).
I think your current system is using 32 bits for addressing (sizeof(unsigned int) / sizeof(int)); my system, using 64 bits, spits "2" as a result (i.e. sizeof(unsigned long int) / sizeof(int)).
No. You can't. The compiler never knows the array size your pointer is pointing to.
Ref: How to find the 'sizeof' (a pointer pointing to an array)?
For the following code:
#include <stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
return 0;
}
what should it print? I am expecting:
2 3 3 4
but the output is:
2 3 5 6
I am expecting the output as 2 3 3 4
because initially the ptr is pointing to the first row of double dimensional array a[][3]. Therefore (*ptr)[1] of first printf will give us 2, like wise (*ptr)[2] will give us 3. But after the ++ptr line it will start pointing to the second element of the first row of a[][3]. Therefore (*ptr)[1] of second line should now give us 3 and likewise (*ptr)[2] should give us 4.
ptr is of type int (*)[3]:
int (*ptr)[3]
The type of ptr specifies how the pointer airthmetic is going to be performed on ptr.
For the following more general case:
int *p;
// ...
int (*ptr)[N] = p;
ptr += M; // same address as p[M * N]
Incrementing the pointer in M results in an address increment of M * N * sizeof(int) and not just M * sizeof(int) as you may have expected.
This is how pointer arithmetic works, because the type of the elements ptr points to is int [N] and not int.
After the statement ++ptr; is executed, ptr points to the third element of a. The increment is done in steps of three elements of type int instead of a single one, that is, in your case, N = 3.
Let's go through this line by line.
int a[][3] = {1, 2, 3, 4, 5, 6};
a has the type "array of array of 3 int". This line is equivalent to
int a[][3] = {{1, 2, 3}, {4, 5, 6}}; /* alternate */
It is clearer with this alternate line that a is an array of arrays. This will help with understanding the next lines.
int (*ptr)[3] = a;
ptr has the type "pointer to array of 3 int". Because of array-to-pointer decay, ptr will point to the first array in a (int (*ptr)[3] = &a[0]).
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
Dereferencing ptr gives a[0], so this will print
2 3
++ptr;
This seems to be where you are confused. Incrementing a pointer to an element makes the pointer point to where the next element would lie if they were in an array. In this case, the current element pointed to and the next element after that are in an array (the element being an array of 3 ints, not a single int). So incrementing the pointer makes it point to the next array of 3 ints (which happens to be a[1]).
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
Now that we know that ptr points to a[1], we can see that (*ptr)[1] is equivalent to a[1][1], which is 5; and that (*ptr)[2] is equivalent to a[1][2], which is 6. So now the total output is:
2 3 5 6
(*ptr)[3] is a pointer to an array of three elements. Below is an analysis of your program.
#include<stdio.h>
int main()
{
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3]=a;
/* First note ptr is a pointer to an array of three integers
* If you had written it like
* int (*ptr)[3];
* ptr=&a[0];
* ,it would have been more obvious.
* But here, you have the freedom to use it interchangeably
*/
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
/* Remember ptr is &a[0], so *ptr is dereferencing &a[0] to gets its value
* However, since ptr is a pointer to an array, its value itself is an array
* So you need to give the index like (*ptr)[1] & (*ptr)[2] to get the second and third values
* (Mind the count starts with zero)
* In essence you are doing,
* printf("%d %d ", *((*ptr)+1*4*8),*((*ptr)+2*4*8)); // 4bytes=4*8 bits
* Here '*ptr' will be substituted with a[0],the starting address an 12 byte block ( 3 integers * 4 bytes per integer)
*/
++ptr;
/* Above step can be written as
* ptr=ptr+1;
* This is pointer arithmetic, so '1' above should be considered as 1 block
* Or in layman's terms move pointer to the next 12byte block.
* In other words advance ptr by (12*8) bits so that it now points to &a[1]
*/
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
/* Follow the same steps for the first print with ptr is &a[1]
*/
return 0;
}
This question already has answers here:
Is an array name a pointer?
(9 answers)
Closed 8 years ago.
i have often heard that array and pointers can be used interchangeable in some situation but the two does not mean the same thing so what are the circumstances in which we can use array as a pointer and vice versa.
Arrays and pointers are never the same thing.
However, under certain circumstances, an array name in your code will "decay" to a pointer to the first element. That means you lose information about the size of the array since a pointer doesn't know how many elements it points to (technically, it only points at one though you can advance through a contiguous array if you can tell where the end is, such as with a length or sentinel value).
Situations in which arrays do not behave like pointers are (for example):
when you do a sizeof: for the array, it's the size of the entire array, for a decayed pointer, it's the size of the pointer.
when you want to move through an array: with a real array, you must use indexing while you can simply increment the pointer.
Consider the following code:
#include <stdio.h>
void fn (int arr[]) {
printf ("sz = %d\n", sizeof(arr));
printf ("#4 = %d\n", arr[4]);
arr = arr + 1;
printf ("#4 = %d\n", arr[4]);
}
int main (void) {
int x[] = {1,2,3,4,5,6,7,8,9};
printf ("sz = %d\n", sizeof(x));
printf ("#4 = %d\n", x[4]);
//x = x + 1; // Cannot do this
printf ("#4 = %d\n", x[4]);
puts("=====");
fn(x);
return 0;
}
which outputs:
sz = 36
#4 = 5
#4 = 5
=====
sz = 4
#4 = 5
#4 = 6
You can see from that the sizeof is different and you can actually move the pointer whereas the array name is at a fixed location (you'll get an error if you uncomment the line that tries to increment it).
The name of an array behaves pretty much like a pointer to the first element. That is it's value, although it has other attributes that are different.
This is most obvious when calling a function. If you have:
float sum_floats(const float *x, size_t num_values);
you can call it with:
float three[] = { 1.f, 2.f, 3.f };
const float sum = sum_floats(three, sizeof three / sizeof *three);
Note how three in the function call "decays" into &three[0], i.e. a pointer to the first element in the array. Note also how sizeof three still works, since three really is an array.
Inside the function, the array has decayed into const float *, the type of the function's argument, and you can no longer use sizeof to get the size of the caller's array (since the function has no idea that the caller used an array).
Typically an array is a container for a number of elements of the same type, while a pointer is the memory address for a memory location that contains a specific value.
When you declare an array like this:
int arr[] = {1, 2, 3, 4, 5};
printf("%d", *arr); /* will print 1 */
printf("%d", arr[0]); /* will print 1 as well */
/*or*/
int arr[5];
you are allocating memory for 5 integers. Take care that the array name by itself acts as a pointer to the first element in the array.
You can achieve the same thing using pointers:
int* arr = new int[5];