Typecasting a pointer variable twice, why? - c

I have found the following code in my lecture book, it works as intended, there is no error, i am just trying to understand it. In the code, we create a char array and an int_pointer. We are able to traverse the char array with the int pointer by typecasting it to a char pointer, such that everytime it gets incremented we move exactly 1 byte forward, instead of 4.
Now my question is why we typecast 2 times. In line 13 (where the comment is) there is the "inner" typecast of (char *) and additionally the "outer" typecast (int *). I understand why the inner typecast is necessary, but why do we need the outer one? I have removed it and yet everything stays the same.
What amazes me even more is that by typecasting it back into an int pointer, the expected length of the referenced data becomes 4 again and yet, when it gets dereferenced it prints out char after char, which indicates that only 1 byte is actually read out, even though we use a pointer that is of type int, which usually reads 4 bytes from where the pointer points to. How can that be?
#include <stdio.h>
int main(){
int i;
char char_array[5] = {'a','b','c','d','e'};
int int_array[5] = {1,2,3,4,5};
char *char_pointer;
int *int_pointer;
char_pointer = (char *) int_array; // Typecast into the
int_pointer = (int *) char_array; // pointer's data type
for (int i=0; i < 5;i++){ // Iterate through the char array with the int_pointer
printf("[integer pointer] points to %p, which contains the char '%c'\n",
int_pointer, *int_pointer);
/* Line 13 */ int_pointer = (int *) ((char *) int_pointer + 1);
}
for (int i=0; i < 5;i++){ // Iterate through the int array with the char_pointer
printf("[char pointer] points to %p, which contains the integer '%d'\n",
char_pointer, *char_pointer);
char_pointer = (char *) ((int *) char_pointer + 1);
} }
OUTPUT
[integer pointer] points to 000000000061FE03, which contains the char 'a'
[integer pointer] points to 000000000061FE04, which contains the char 'b'
[integer pointer] points to 000000000061FE05, which contains the char 'c'
[integer pointer] points to 000000000061FE06, which contains the char 'd'
[integer pointer] points to 000000000061FE07, which contains the char 'e'
[char pointer] points to 000000000061FDE0, which contains the integer '1'
[char pointer] points to 000000000061FDE4, which contains the integer '2'
[char pointer] points to 000000000061FDE8, which contains the integer '3'
[char pointer] points to 000000000061FDEC, which contains the integer '4'
[char pointer] points to 000000000061FDF0, which contains the integer '5'

You would be very unlikely to see code like that outside an environment where they're just trying to teach you how things may work under the covers :-)
But I'll answer one question at least:
the expected length of the referenced data becomes 4 again and yet, when it gets dereferenced it prints out char after char, which indicates that only 1 byte is actually read out ...
No, the expression *int_pointer will read out four bytes (or as many bytes as is needed to make an int). What you're seeing there is the undefined behaviour of mismatching a format specifier with a different data type to what's expected. The standard is quite explicit (ISO C11 in this case):
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
What's probably happening with your code in this case is that it's just using the least significant eight bits of the int.
And, just as an aside, it doesn't actually make any difference what the original type of a pointer is when you cast it to another type and perform arithmetic on it (expect for the possibility of having non-aligned pointers which is fatal in some environments).
The arithmetic is performed on the cast type, not the original:
int_pointer = (int *) ((char *) int_pointer + 1);
char_pointer = (char *) ((int *) char_pointer + 1);
// \___________________/
// |
// This is what you're adding one to,
// the pointer as if it was another type.
The first of those advances the pointer by one memory location regardless of the fact it uses an int pointer, because the additice expression is being given a char pointer due to the cast.
Similarly, the second advances by sizeof(int), even though it's adjusting (eventually) a char pointer.

Your question is answered by #paxdiablo, with a very well conceptual explanation but I'll add a couple of lines to make it easier to visualize.
Breaking down the line int_pointer = (int *)((char *) int_pointer + 1);:
// set the int_pointer to point to the starting address of the char_array
int_pointer = (int *) char_array;
// treat the int_pointer as if it's a character pointer
(char *) int_pointer
// add 1 to that pointer *** adds 1 byte only ***
(char *) int_pointer + 1
// then, switch back and treat that pointer as if it's an integer pointer again
int_pointer = (int *) ((char *) int_pointer + 1);
And, breaking down the line char_pointer = (char *)((int *) char_pointer + 1);:
// set the char_pointer to point to the starting address of the int_array
char_pointer = (char *) int_array;
// treat the char_pointer as if it's an integer pointer
(int *) char_pointer
// add 1 to that pointer *** adds 4 bytes ***
(int *) char_pointer + 1
// then, switch back and treat that pointer as if it's a character pointer again
char_pointer = (char *)((int *) char_pointer + 1);
Then the magic of the printf function comes into play... If a printf function is to print the value of a dereferenced pointer, printf treats that same address according to the corresponding format specifier:
printf("dereferencing same address as int %d and as char %c\n", *char_pointer, *char_pointer);
// printf takes the same memory address, namely the value of "char_pointer"
// first, treats the 4 bytes as if it's an integer
// then, treats the single byte as if it's a character
and same as above;
printf("dereferencing same address as int %d and as char %c\n", *int_pointer, *int_pointer);
// printf takes the same memory address, namely the value of "int_pointer"
// first, treats the 4 bytes as if it's an integer
// then, treats the single byte as if it's a character

Related

Why char pointer increments by one byte though its size is 8?

void main() {
char var = 10;
char *ptr = &var;
printf("Pointer address before increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
ptr++;
printf("Pointer address after increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
}
Output:
Pointer address before increment:0x7fffb997144f
sizeof(ptr):8
Pointer address after increment:0x7fffb9971450
sizeof(ptr):8
Why does the char pointer increment by one byte only? Its size is 8, right?
When ptr is declared, the compiler allocates 8 bytes to it. When we increment it by 1, it increments based on the datatype. Why? How does this works?
For starters to output values of the type size_t you need to use the conversion specifier zu instead of d
printf("sizeof(ptr):%zu\n",sizeof(ptr));
^^^
Incremented pointer points to the memory after the object it points to. That is the value of a pointer of the type T * is incremented by the value sizeof( T ).
Consider for example accessing array elements.
T a[N];
The expression a[i] evaluates like +( a + i ). So the value of the pointer is incremented by i * sizeof( T ).
This is called the pointer arithmetic,
As for the size of objects of the type char then according to the C Standard sizeof( char ) is always equal to 1.
Also consider the following demonstration program.
#include <stdio.h>
int main( void )
{
char s[] = "Hello";
for ( const char *p = s; *p != '\0'; ++p )
{
putchar( *p );
}
putchar( '\n' );
}
Its output is
Hello
If the pointer p was incremented by the value sizeof( char * ) then you could not output the array using the pointer.
For pointer arithmetics, what matters is not the sizeof the pointer, but the size of the type it points to:
T a[10]; T *p = a; defines a pointer p to an array of objects of type T.
p contains the memory address of the first element of a.
The next element's address is sizeof(T) bytes farther, so incrementing the pointer p by 1 increments the memory address by sizeof(*p).
Here is a modified version:
#include <stdio.h>
int main() {
char char_array[2] = "a";
char *char_ptr = char_array;
printf("sizeof(char_ptr): %zu\n", sizeof(char_ptr));
printf("char_ptr before increment: %p\n", (void *)char_ptr);
printf("sizeof(*char_ptr): %zu\n", sizeof(*char_ptr));
char_ptr++;
printf("char_ptr after increment: %p\n", (void *)char_ptr);
int int_array[2] = { 1, 2 };
int *int_ptr = int_array;
printf("\nsizeof(int_ptr): %zu\n", sizeof(int_ptr));
printf("int_ptr before increment: %p\n", (void *)int_ptr);
printf("sizeof(*int_ptr): %zu\n", sizeof(*int_ptr));
int_ptr++;
printf("int_ptr after increment: %p\n", (void *)int_ptr);
return 0;
}
Output (64 bits):
sizeof(char_ptr): 8
char_ptr before increment: 0x7fff52c1f7ce
sizeof(*char_ptr): 1
char_ptr after increment: 0x7fff52c1f7cf
sizeof(int_ptr): 8
int_ptr before increment: 0x7fff52c1f7c0
sizeof(*int_ptr): 4
int_ptr after increment: 0x7fff52c1f7c4
Output (32 bits):
sizeof(char_ptr): 4
char_ptr before increment: 0xbffc492e
sizeof(*char_ptr): 1
char_ptr after increment: 0xbffc492f
sizeof(int_ptr): 4
int_ptr before increment: 0xbffc4930
sizeof(*int_ptr): 4
int_ptr after increment: 0xbffc4934
That's because a charactor occupies 1 byte, while a pointer to charactor is a pointer, not a charactor or something else, that means it stored a memory adress, so it occupies 8 bytes. Also all kinds of pointer is 8 bytes on your machine.
What are pointers?
Briefly the pointers are a special types of variables for holding memory addresses and its bit wide or byte size that the compilers allocate may vary depending on the platform. If you size a pointer using the sizeof operator in an 8-bit architecture for example, in most devices you will get 2 bytes, that is, a pointer can hold an address value up to 64kB. This is logically big enough to hold address value for devices that only has up to 64kB of ROM and up to a few kBs of RAM.
Since the architecture in which you compile your code is a 64-bit architecture, the system registers are 64-bits wide and it's wide enough to hold very large address values (2 * 10^64). Since its big enough it will naturally size 64-bits / 8 bytes.
As said the pointers are special objects, so you cannot assign kinds of constants like
int* ptr = 0x7fffb997144f; // Compilers will not allow this
Compilers will not allow this because the pointers are not regular kind of variables. So in order to assign a constant address value you must cast it as pointer like in the following example:
int* ptr = (int*) 0x7fffb997144f; // Compilers will allow this
How the pointers are incremented
It depends on the byte size of the type to which a pointer points. That is;
1 for char types
2 for short int types
4 for long types
8 for long long types
Some type sizes like of int and float types may vary depending on the platform.
Now that we know about pointers and how it is incremented let's make an example for each type above. Let's assume that the start address for each example is 0x7fffb997144f.
For char types
char vars[5];
char* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971450
ptr++; // 0x7fffb9971451
For short int types
short int vars[5];
short int* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971451
ptr++; // 0x7fffb9971453
For long types
long vars[5];
long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971454
ptr++; // 0x7fffb9971458
For long long types
long long vars[5];
long long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971458
ptr++; // 0x7fffb997145f

Assigning Variable to Pointer vs Assiging &variable to Pointer

I am now learning about pointers. This is the sample code from a book:
#include <stdio.h>
int main()
{
int i;
char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
int int_array[5] = {1, 2, 3, 4, 5};
char *char_ptr;
int *int_ptr;
char_ptr = char_array;
int_ptr = int_array;
for(i=0; i < 5; i++) {
printf("[integer pointer] points to %p, which contains the integer %d\n", int_ptr, *int_ptr + 1);
int_ptr = int_ptr + 1;
}
for(i=0; i <5; i++) {
printf("[char pointer] points to %p, which contains the char '%c'\n", char_ptr, *char_ptr);
char_ptr = char_ptr + 1;
}
}
Q. Would char *char_ptr = char_array; change how this code functions in any way or is this the same thing as lines shown above?
Q. Other sample codes from this book also assigns &variable to a pointer, which from I understand means to store the address of a variable to that pointer, (e.g. char_ptr = &char_array;). This sample just assigns the variable itself to the pointer, but this program still manages to print the memory addresses that the pointer points to. Why or why not use char_ptr = &char_array; in this context? Or does it not make a difference?
> kingvon#KingVon:~/Desktop/asm$ gcc pointertypes.c
> kingvon#KingVon:~/Desktop/asm$ ./a.out [integer pointer] points to
> 0x7ffc225227a0, which contains the integer 2 [integer pointer] points
> to 0x7ffc225227a4, which contains the integer 3 [integer pointer]
> points to 0x7ffc225227a8, which contains the integer 4 [integer
> pointer] points to 0x7ffc225227ac, which contains the integer 5
> [integer pointer] points to 0x7ffc225227b0, which contains the integer
> 6 [char pointer] points to 0x7ffc225227c3, which contains the char 'a'
> [char pointer] points to 0x7ffc225227c4, which contains the char 'b'
> [char pointer] points to 0x7ffc225227c5, which contains the char 'c'
> [char pointer] points to 0x7ffc225227c6, which contains the char 'd'
> [char pointer] points to 0x7ffc225227c7, which contains the char 'e'
> kingvon#KingVon:~/Desktop/asm$
Edit- typo
A. Yes, this is same things as lines shown above.
A. From C11 Standards#6.3.2.1p3 [emphasis added]
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. ....
So, in these statements
char_ptr = char_array;
int_ptr = int_array;
char_array is converted to pointer of type char * that points to the initial element of the char_array and int_array is converted to pointer of type int * that points to the initial element of the int_array.
For Q1:
Q. Would char *char_ptr = char_array; change how this code functions in any way or
is this the same thing as lines shown above?
char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
char *char_ptr; // declaration
char_ptr = char_array; // assignment
Ans: Both are same.
In the first one(in question) char_ptr declaration and initialization are done in same line and in second one they are done separately.
For Q2:
Why or why not use char_ptr = &char_array; in this context? Or does it not make a difference?
Ans: In the code above shown char_array is an array of 5 characters, when you use its name to assign to a pointer
it basically means you are assigning address of its first element, so the expressions
char_ptr = char_array; // 1. decl & init done separately
char *char_ptr = char_array; //2. decl & init done same line
char *char_ptr = &char_array[0]; //3. same as 2
char *char_ptr = &char_array; // 4. this is not the correct way will give you warning about this usage, its needs char (*)[5] ptr;
all print the address of the starting element of the array.
The expressions
char *char_ptr = &char_array[0]; and char *char_ptr = &char_array; are different but they give the same address
Q. Would char *char_ptr = char_array; change how this code functions
in any way or is this the same thing as lines shown above?
*char_ptr = char_array; is the same thing as the lines shown above.
Q. Other sample codes from this book also assigns &variable to a pointer, which from I understand means to store the address of a variable to that pointer, (e.g. char_ptr = &char_array;). This sample just assigns the variable itself to the pointer, but this program still manages to print the memory addresses that the pointer points to. Why or why not use char_ptr = &char_array; in this context? Or does it not make a difference?
What you want to do here is assigning the address of a variable (an array) to a pointer. In order to get the address of an array, you simply use the array name, so you don't need the & operator to get the address of an array. Refer to this link for more details.
The & operator is used in case you want to use a pointer to point to a variable. Refer to this article to understand more about * and & operators
char *p1;
char *p2;
char var;
char arr[5];
p1 = &var
p2 = arr;
Edit: Add another way to initialize pointer
char var;
char arr[5];
char *p1 = &var; // char *p1 = var is not correct
char *p2 = arr;

Why can't I access a pointer to pointer for a stack array?

Please take a look at the following code. It tries to pass an array as a char** to a function:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
The fact that I can only get it to compile by explicitly casting &test2 to char** already hints that this code is wrong.
Still, I'm wondering what exactly is wrong about it. I can pass a pointer to a pointer to a dynamically allocated array but I can't pass a pointer to a pointer for an array on the stack. Of course, I can easily work-around the problem by first assigning the array to a temporary variable, like so:
char test[256];
char *tmp = test;
test[0] = 'B';
printchar(&tmp);
Still, can someone explain to me why it doesn't work to cast char[256] to char** directly?
test is an array, not a pointer, and &test is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
The array is the operand of sizeof.
The array is the operand of &.
The array is a string literal used to initialize an array.
In &test, the array is the operand of &, so the automatic conversion does not occur. The result of &test is a pointer to an array of 256 char, which has type char (*)[256], not char **.
To get a pointer to a pointer to char from test, you would first need to make a pointer to char. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Another way to think about this is to realize that test names the entire object—the whole array of 256 char. It does not name a pointer, so, in &test, there is no pointer whose address can be taken, so this cannot produce a char **. In order to create a char **, you must first have a char *.
Because test is not a pointer.
&test gets you a pointer to the array, of type char (*)[256], which is not compatible with char** (because an array is not a pointer). This results in undefined behavior.
The type of test2 is char *. So, the type of &test2 will be char ** which is compatible with the type of parameter x of printchar().
The type of test is char [256]. So, the type of &test will be char (*)[256] which is not compatible with the type of parameter x of printchar().
Let me show you the difference in terms of addresses of test and test2.
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Output:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Point to note here:
The output (memory address) of test2 and &test2[0] is numerically same and their type is also same which is char *.
But the test2 and &test2 are different addresses and their type is also different.
The type of test2 is char *.
The type of &test2 is char **.
x = &test2
*x = test2
(*x)[0] = test2[0]
The output (memory address) of test, &test and &test[0] is numerically same but their type is different.
The type of test is char [256].
The type of &test is char (*) [256].
The type of &test[0] is char *.
As the output shows &test is same as &test[0].
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Hence you are getting segmentation fault.
You cannot access a pointer to a pointer because &test is not a pointer—it's an array.
If you take the address of an array, cast the array and the address of the array to (void *), and compare them, they will (barring possible pointer pedantry) be equivalent.
What you're really doing is similar to this (again, barring strict aliasing):
putchar(**(char **)test);
which is quite obviously wrong.
Your code expects the argument x of printchar to point to memory that contains a (char *).
In the first call, it points to the storage used for test2 and is thus indeed a value that points to a (char *), the latter pointing to the allocated memory.
In the second call, however, there is no place where any such (char *) value might be stored and so it is impossible to point to such memory. The cast to (char **) you added would have removed a compilation error (about converting (char *) to (char **)) but it would not make storage appear out of thin air to contain a (char *) initialized to point to the first characters of test. Pointer casting in C does not change the actual value of the pointer.
In order to get what you want, you have to do it explicitly:
char *tempptr = &temp;
printchar(&tempptr);
I assume your example is a distillation of a much larger piece of code; as an example, perhaps you want printchar to increment the (char *) value that the passed x value points to so that on the next call the next character is printed. If that isn't the case, why don't you just pass a (char *) pointing to the character to be printed, or even just pass the character itself?
Apparently, taking the address of test is the same as taking the address of test[0]:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("[printchar] Address of pointer to pointer: %p\n", (void *)x);
printf("[printchar] Address of pointer: %p\n", (void *)*x);
printf("Test: %c\n", **x);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
printf("[main] Address of test: %p\n", (void *)test);
printf("[main] Address of the address of test: %p\n", (void *)&test);
printf("[main] Address of test2: %p\n", (void *)test2);
printf("[main] Address of the address of test2: %p\n", (void *)&test2);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar(&test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Compile that and run:
forcebru$ clang test.c -Wall && ./a.out
test.c:25:15: warning: incompatible pointer types passing 'char (*)[256]' to
parameter of type 'char **' [-Wincompatible-pointer-types]
printchar(&test); // crashes because *x in printchar() has an inva...
^~~~~
test.c:4:30: note: passing argument to parameter 'x' here
static void printchar(char **x)
^
1 warning generated.
[main] Address of test: 0x7ffeeed039c0
[main] Address of the address of test: 0x7ffeeed039c0 [THIS IS A PROBLEM]
[main] Address of test2: 0x7fbe20c02aa0
[main] Address of the address of test2: 0x7ffeeed039a8
[printchar] Address of pointer to pointer: 0x7ffeeed039a8
[printchar] Address of pointer: 0x7fbe20c02aa0
Test: A
[printchar] Address of pointer to pointer: 0x7ffeeed039c0
[printchar] Address of pointer: 0x42 [THIS IS THE ASCII CODE OF 'B' in test[0] = 'B';]
Segmentation fault: 11
So the ultimate cause of the segmentation fault is that this program will try to dereference the absolute address 0x42 (also known as 'B'), which your program doesn't have permission to read.
Although with a different compiler/machine the addresses will be different: Try it online!, but you'll still get this, for some reason:
[main] Address of test: 0x7ffd4891b080
[main] Address of the address of test: 0x7ffd4891b080 [SAME ADDRESS!]
But the address that causes the segmentation fault may very well be different:
[printchar] Address of pointer to pointer: 0x7ffd4891b080
[printchar] Address of pointer: 0x9c000000942 [WAS 0x42 IN MY CASE]
The representation of char [256] is implementation dependent. It is must not be the same as char *.
Casting &test of type char (*)[256] to char ** yields undefined behavior.
With some compilers, it may do what you expect, an on others not.
EDIT:
After testing with gcc 9.2.1, it appears that printchar((char**)&test) passes in fact test as value cast to char**. It is as if the instruction was printchar((char**)test). In the printchar function, x is a pointer to the first char of the array test, not a double pointer to the first character. A double de-reference x result in a segmentation fault because the 8 first bytes of the array do not correspond to a valid address.
I get the exact same behavior and result when compiling the program with clang 9.0.0-2.
This may be considered as a compiler bug, or the result of an undefined behavior whose result might be compiler specific.
Another unexpected behavior is that the code
void printchar2(char (*x)[256]) {
printf("px: %p\n", *x);
printf("x: %p\n", x);
printf("c: %c\n", **x);
}
The output is
px: 0x7ffd92627370
x: 0x7ffd92627370
c: A
The weird behavior is that x and *x have the same value.
This is a compiler thing. I doubt that this is defined by the language.

C Double Typecast

Here's this code from the Art of Exploitation book by Jon Erikson. I understand the typecast on the second line makes the compiler leave you alone about data types. What I'm not sure about is why double typecasting is necessary on the bottom line.
int *int_pointer;
int_pointer = (int *) char_array;
for(i=0; i < 5; i++)
printf("[integer pointer] points to %p, which contains the char '%c'\n", int_pointer, *int_pointer);
int_pointer = (int *) ((char *) int_pointer + 1);
I am going to assume it's because leaving it like so without the (int *) would make it increment by the correct data type character, but is this not what you want? Why typecast back to int?
And what's up with the * inside the parenthesis? Is this de-referencing the data in the variable? Some explanation would be kindly appreciated.
It's not typecasting to int or char, it's typecasting the pointer to a char pointer or int pointer.
When you add one to a pointer, it advances to the next item being pointed at, by scaling the increment based on the type of the item.
If the items are int, it advances by the size of an int. This is probably 4 or 8 in the current environment but will hopefully will be larger in future so we can stop messing about with bignum libraries :-)
If the items are of type char, it advances by one (sizeof(char) is always one, since ISO C defines a byte as the size of a char rather than eight bits).
So, if you have four-byte int types, there's a big difference between advancing an int pointer and a char pointer. For example, consider the following code:
int *p = 0; // bad idea but shows the concept.
p = p + 1; // p is now 4.
p = (int*)(((char*)p) + 1) // p is now 5.
That last statement breaks down as:
(char*)p - get a char pointer version of p (a)
a + 1 - add one to it (b)
(int*)b - cast it back to an int pointer (c)
p = c - replace p with that value

In C, what does a variable declaration with two asterisks (**) mean?

I am working with C and I'm a bit rusty. I am aware that * has three uses:
Declaring a pointer.
Dereferencing a pointer.
Multiplication
However, what does it mean when there are two asterisks (**) before a variable declaration:
char **aPointer = ...
Thanks,
Scott
It declares a pointer to a char pointer.
The usage of such a pointer would be to do such things like:
void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x
Here's another example:
char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome
Use of ** with arrays:
char** array = malloc(sizeof(*array) * 2); //2 elements
(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]
printf("%s", array[1]); //outputs There
The [] operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1] would be evaluated is as follows:
array[1] == *(array + 1);
This is one of the reasons why array indices start from 0, because:
array[0] == *(array + 0) == *(array);
C and C++ allows the use of pointers that point to pointers (say that five times fast). Take a look at the following code:
char a;
char *b;
char **c;
a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"
The variable a holds a character. The variable b points to a location in memory that contains a character. The variable c points to a location in memory that contains a pointer that points to a location in memory that contains a character.
Suppose that the variable a stores its data at address 1000 (BEWARE: example memory locations are totally made up). Suppose that the variable b stores its data at address 2000, and that the variable c stores its data at address 3000. Given all of this, we have the following memory layout:
MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
It declares aPointer as a pointer to a pointer to char.
Declarations in C are centered around the types of expressions; the common name for it is "declaration mimics use". As a simple example, suppose we have a pointer to int named p and we want to access the integer value it's currently pointing to. We would dereference the pointer with the unary * operator, like so:
x = *p;
The type of the expression *p is int, so the declaration of the pointer variable p is
int *p;
In this case, aPointer is a pointer to a pointer to char; if we want to get to the character value it's currently pointing to, we would have to dereference it twice:
c = **aPointer;
So, going by the logic above, the declaration of the pointer variable aPointer is
char **aPointer;
because the type of the expression **aPointer is char.
Why would you ever have a pointer to a pointer? It shows up in several contexts:
You want a function to modify a pointer value; one example is the strtol library function, whose prototype (as of C99) is
long strtol(const char * restrict str, char ** restrict ptr, int base);
The second argument is a pointer to a pointer to char; when you call strtol, you pass the address of a pointer to char as the second argument, and after the call it will point to the first character in the string that wasn't converted.
Remember that in most contexts, an expression of type "N-element array of T" is implicitly converted to type "pointer to T", and its value is the address of the first element of the array. If "T" is "pointer to char", then an expression of type "N-element array of pointer to char" will be converted to "pointer to pointer to char". For example:
void foo(char **arr)
{
size_t i = 0;
for (i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
void bar(void)
{
char *ptrs[N] = {"foo", "bar", "bletch", NULL};
foo(ptrs); // ptrs decays from char *[N] to char **
}
You want to dynamically allocate a multi-dimensional array:
#define ROWS ...
#define COLS ...
...
char **arr = malloc(sizeof *arr * ROWS);
if (arr)
{
size_t i;
for (i = 0; i < ROWS; i++)
{
arr[i] = malloc(sizeof *arr[i] * COLS);
if (arr[i])
{
size_t j;
for (j = 0; j < COLS; j++)
{
arr[i][j] = ...;
}
}
}
}
It means that aPointer points to a char pointer.
So
aPointer: pointer to char pointer
*aPointer :pointer to char
**aPointer: char
An example of its usage is creating a dynamic array of c strings
char **aPointer = (char**) malloc(num_strings);
aPointer gives you a char, which can be used to represent a zero-terminated string.
*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]
This is a pointer to a pointer to char.

Resources