Character array and pointer - c

The code snippet is given as:
char *s[] = {"program", "test", "load", "frame", "stack", NULL};
char **p = s + 2;
We need to find the output of following statement:
printf("%s", p[-2] + 3);
What does p[-2] refer to?

char *s[] = {"program","test","load","frame","stack",NULL};
char **p = s + 2
printf("%s", p[-2] + 3);
The variable s is an array of char* pointers.
The variable p is a pointer to a pointer. Pointer arithmetics downgrades the array s to a char**, initializing p to a value of two times the size of a char**. On a 32bit machine, if s points to 1000, p will point to 1008.
The expression p[-2] is equivalent to *(p - 2), returning a simple pointer to a char*. In this case, a value pointing to the first element of the strings array: "program".
Finally, since *(p - 2) is the expression pointing to the first letter of the string "program", *(p - 2) + 3 points to the fourth letter of that word: "gram".
printf("%s", *(p - 2) + 3); /* prints: gram */

Did you try compiling your code? Once the syntax errors are fixed, the output is gram.
#include <stdio.h>
int main()
{
char *s[] = {"program","test","load","frame","stack",NULL};
char **p = s + 2;
printf("%s",p[-2] + 3);
return 0;
};
See http://ideone.com/eVAUv for the compilation and output.

Related

How to access different elements in char** in C?

I am given an array of strings in the form of a pointer to a pointer of a character (that is, char **). I wish to access each element in the array,
char **strings = {"hello", "bye", "whatusp"};
printf("%s\n", *(&strings));
printf("%s\n", *(&strings + 1));
I notice that the first printf() works, as it outputs "hello" for me, but the second doesn't output anything. The +1 does increment by 8 instead of 1, since the address is in bytes. How can I access an arbitrary element in such a double pointer?
Just as simple as:
char *strings[] = {"hello", "bye", "whatusp"};
printf("%s\n", strings[0]);
printf("%s\n", strings[1]);
printf("%s\n", strings[2]);
First of all, the line
char **strings = {"hello", "bye", "whatusp"};
is wrong. If you want to declare an array of 3 pointers to string literals, then it should be the following instead:
char *strings[3] = {"hello", "bye", "whatusp"};
In the previous line, you can omit the 3, because the compiler is smart enough to count the number of elements itself, since you are initializing the array.
The lines
printf("%s\n", *(&strings));
printf("%s\n", *(&strings + 1));
are also wrong, because when using printf with the %s format specifier, you must provide a pointer to a string, i.e. a char *. However, you are providing a char** instead in both lines.
The expression *(&strings) will evaluate to a char ** for the following reason:
The expression &strings will evaluate to a pointer to strings. Since strings itself is an array of 3 pointers to char, a pointer to strings is a pointer to an array of 3 pointers to char. Afterwards, you are applying the indirection operator * on this data type, so that the result of this operation is an array of 3 pointers to char. When passing this data type to printf, the array will decay to a pointer to the first element of the array, i.e. to a pointer to a pointer to a char (which is a char**).
You should simply write the following instead:
printf( "%s\n", strings[0] );
printf( "%s\n", strings[1] );
The expression strings[1] is equivalent to *(strings+1).
char **strings is a pointer to a pointer to char, not array of pointers to char, your compiler should have given you a warning anyways, if not you should enable them.
For that assignment to work, you will need to have an array of pointers, char *strings[] or if you want to use plain pointer notation (array notation is using pointer arithmetic in the background though), you could dynamically allocate memory for the first dimension.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
int main(void)
{
char **strs = NULL;
if ((strs = malloc(SIZE * sizeof(char *))) == NULL) /* check malloc result */
{
exit(EXIT_FAILURE);
}
*strs = "hello"; /* assignment makes sense in this case but you cant modify the string since its read-only*/
*(strs + 1) = "bye";
*(strs + 2) = "whatsup";
for (int i = 0; i < SIZE; i++)
{
puts(*(strs + i));
}
/* Alternative that will allocate space for each string if you need to store them or modify them later */
/* for (int i = 0; i < 3; i++)
{
if ((*(strs + i) = malloc(YOUR_STRINGS_LENGTH)) == NULL)
{
exit(EXIT_FAILURE);
}
snprintf(*(strs + i), YOUR_STRINGS_LENGTH, "string");
}
*/
return 0;
}
I am given an array of strings in the form of a pointer to a pointer of a character (that is, char **)
There is no such thing: a char** is just a pointer. It is not an array.
if thing is char** then
*thing is char* and **thing is, as declared, a char.
An array can be seen as a pointer, but a pointer is not an array.
note: the prototype for main is in general
int main( int argc, char** argv)
so what you need to do is the same as every C program gets from the system.
Example
To have char** as an array of pointers to char you must build it
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char* array[] = {
"I", "wish", "to", "access", "each", "element",
"in", "the", "array"
};
int N = sizeof(array) / sizeof(char*);
printf("%d strings in total\n\n", N);
char** strings = (char**)malloc(N * sizeof(char*));
for (int i = 0; i < N; i=i+1)
*(strings+i) = *(array + i);
for (int i = 0; i < N; i=i+1)
printf("%3d %s\n", 1 + i, *(i + strings));
// pointer is not an array
char thing = '#';
char* p = &thing;
char** pp = &p;
printf("\n\nthing is '%c', *p is '%c', **pp is '%c'\n",
thing, *p, **pp);
return 0;
}
output
9 strings in total
1 I
2 wish
3 to
4 access
5 each
6 element
7 in
8 the
9 array
thing is '#', *p is '#', **pp is '#'
In particular note this lines
char** strings = (char**)malloc(N * sizeof(char*));
for (int i = 0; i < N; i=i+1)
*(strings+i) = *(array + i);
where is defined that strings is an area of the needed size and than the pointers are initialized to the strings of the input array.

Difference between 2D char Array and char** (OR, 3D char Array and char*** etc)

Firstly, I've already reviewed these:
How are multi-dimensional arrays formatted in memory?
Memory map for a 2D array in C
From there, it is known that a 2D array is not the same as char** but in memory they look exactly same. This sounds strange and so I've researched the following:
#include <stdio.h>
char func(char** m) {
return m[0][0]; //only works for char**, already discussed in the other SO question
}
int main() {
//char a[4][2]; //a 2D char array
int row = 4, col = 2; //char**
char** a = malloc(row * sizeof(char*));
int i;
for (i = 0; i < row; i++) {
a[i] = malloc(col * sizeof(char));
}
//checking the output
printf(" &a = %u\n", &a);
printf(" &a[0] = %u\n", &a[0]);
printf("&a[0][0] = %u\n", &a[0][0]);
printf(" a = %u\n", a);
printf(" a[0] = %u\n", a[0]);
//printf(" a[0][0] = %u\n", a[0][0]); //char value in a[0][0], here a garbage value
//char m = func(a); //only works for char**, already discussed in the other SO question
return 0;
}
Possible output for char** :
&a = 3209288 // &a
&a[0] = 4083720 // &(*(a+0)) = a
&a[0][0] = 4083784 // &(*(*(a+0)+0)) = *a
a = 4083720 // a
a[0] = 4083784 // *(a+0) = *a
Possible output for 2D char array :
&a = 3473104 // &a
&a[0] = 3473104 // a
&a[0][0] = 3473104 // *a
a = 3473104 // a
a[0] = 3473104 // *a
It is easy to understand the output of char**. But the output of 2D char array looks strange though it was discussed in the other SO question. I cannot think of a pointer x of whatever data-type when,
x = &x = *x
and all the 3 things physically reside in the same block of memory. Hope that my confusion is understandable. Can anyone explain the mystery?
When you use name of the array is any expression except &array and sizeof array this name will be automaticly converted to pointer to the first element of the array (char [5][10] will be converted to char (*)[10]). Address of this pointer will be equal to the adress of entire array.
So, "sizeof (char [5][10]) == 50", there is no additional pointers.
char arr[5][10];
&a = 3473104 // Address of entire array, (char (*)[5][10])
&a[0] = 3473104 // Address of first row, (char (*)[10])
&a[0][0] = 3473104 // Address of first char, (char *)
a = 3473104 // "a", (char [5][10]), converted to "&a[0]", (char (*)[10])
a[0] = 3473104 // "a[0]", (char[10]), converted ro "&a[0][0]", (char *)

Pointer arithmetic and address

I have come across a code which goes like :
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5};
int *ptr = (int*)(&a + 1);
int *ptr2 = (int*) &a;
ptr2 +=1 ;
printf("%d %d %d \n", *(a + 1),*(ptr - 1) ,*ptr2 );
return 0;
}
The pointer arithmetic does it for me except this line :
int *ptr = (int*)(&a + 1);
Is it undefined behaviour ?
Why do we get 5 on dereferencing *(ptr - 1) ?
The size of a is "5 ints". So &a + 1 refers to the first memory location past all of a, since the pointer arithmetic is done in units of the size of a.
Try it out!
int a[5] = {1, 2, 3, 4, 5};
printf("%#x, %#x, %#x, %#x\n", a, &a, a+1, &a+1);
0xbfa4038c, 0xbfa4038c, 0xbfa40390, 0xbfa403a0
So what does that tell us?
0xbfa4038c == 0xbfa4038c which means a == &a. This is the address of the first element in the array or a[0].
We know that the size of an int is 4, and you know that *(a+1) == a[1] (the second element in the array) and this is proven by:
0xbfa4038c + 0x4 = 0xbfa40390 which means a + one int = address of the next element
Thus if we see &a+1 == 0xbfa403a0, that means we're ((0xa0-0x8c)/4) = 5 elements into the array. You know that a[5] is invalid, so that means we're one passed the end of the array.
so if you take:
int *ptr = (int*)(&a + 1); //one passed last element in the array
printf("%d",*(ptr - 1));//back up one, or last element in the array and deference
That's why you get 5
For an array of n elements of type T, then 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’;
int *ptr = (int*)(&a + 1); //&a-> address whole array, size=20 bytes,
//ptr=&a+1: next element =adress of a +20 bytes.
//ptr - 1 = address of a +16 = address of last a's element = address of 5

Pointers manipulation in c

I have a doubt in pointers manipulation...
main()
{ int x=10; // extra line added...
char *p=x;
printf("%d", &p)
printf("%d", &p[0]);
printf("%d" , &p[1]);
}
This code gives output
Address of 10..
10
11
how are the last two outputs are coming.. Can anyone explain it to me ..?
Code changed.....
This is Undefined Behavior.
The pointer needs to point to something valid before some value can be added to that location.
char a = 10;
char *p = &a;
Will explain two scenarios:
Scenario 1: char * p = x;
x == 10, p is a char pointer which is initialized with 10 (an address which user program can't access): p == 10
The value of p (ie, *p) will lead to segmentation fault (being invalid memory reference)
p[0] == *(p + 0) and &p[0] == (p+0) == p which is 10.
Hence printf("%p", &p[0]) will give you 10.
p[1] == *(p + 1) and &p[1] == (p+1)
Since, p is a character pointer, it gets increments by sizeof(char), ie 1
Hence printf("%p", &p[1]) will give you 10+1 = 11
Scenario 2: char * p = &x;
Here p is a char pointer pointing to integer x
Value of x = 10
Address of x = 1000 (assume)
Hence p = 1000
p[0] == *(p + 0) and &p[0] == (p+0) == p
Hence printf("%p", &p[0]) will give you 1000
p[1] == *(p + 1) and &p[1] == (p+1)
Since, p is a character pointer, it gets increments by sizeof(char), ie 1
ie &p[1] == 1000+1 == 1001
p and &p[0] will be evaluated to same address (address of first element of array) which is 10.
So &p[0] will be evaluated to 10 and &p[1] to &p[0] + sizeof(char) which is 11
Your code will most likely segfault though when you dereference p (*p).
Following code will always print True.
main()
{
int* p;
printf("%s\n",p == &p[0] ? "True" : "False");
}
Some errors in your code:
int x = 10;
char * p = &x; // error 1 - you was assigning int to pointer
printf("%p\n", &p); // error 2 - you printing address of pointer (char **),
// so different format string is needed
printf("%p\n", &p[0]); // same error 2 - printing address of first byte in int x
printf("%p\n" , &p[1]); // same error 2 - printing address of second byte in int x
printf("%d", &p[0]);
printf("%d" , &p[1]);
it will print out the address that p is pointered on..
because char *p=x; while x = 10;
then ,, &p[0] = 10, &p[1] = 11 &p[2] = 12 , and so on..
printf("%d", &p);
I'm not so sure about this, but as i know it will print out the value contained in memory 10 in my case = 10000
printf("%d", p);
it will print out the 10, which is the *p value;
cmiiw
char *p=10;
The code at present has undefined behavior. Pointer p is not pointing to any valid memory location to initialize 10 in that location.
With that said, both p, &p[0] yields the same memory location.

c pointer with string

Trying to learn pointers better I wrote this code. The intention was to print one character of a string at a time in a for loop. Again trying to learn how to increment a pointer and then dereference the pointer.
char *string = "abcdef";
char *pointer = &string;
for (int i =0; i < 4; i++)
{
printf("the next charater is %c\n", *pointer);
pointer = (char *)pointer + sizeof(char);
}
want it to print:
the next charater is a
the next charater is b
the next charater is c
the next charater is d
char *pointer = &string;
should be
char *pointer = string;
string is a pointer variable that contains the address of your string literal. You want the address of the string literal, so you should simply copy the value in string - not take the address of the local pointer variable - your current code gives you a pointer to a pointer to a string.
Additionally, pointer = (char *)pointer + sizeof(char); doesn't require a cast, and it should not use sizeof(char). When incrementing a variable of type pointer to X, incrementing it by one will increment it by sizeof(X) bytes - increment by one to point at the next X. Use pointer += 1; or ++pointer instead.
If you want to print (or otherwise process) the whole string one char at a time, you may use the following idiom:
char *p = /* ... */;
while (p && *p) {
printf("next char: %c\n", *p++);
}
The condition first tests whether p is NULL, i.e. if it is wise to dereference p at all. If p is not NULL, *p tests whether you already reached the end of the string, denoted by the '\0' character, which happens to be 0.
If you want to use pointer to pointer to string then you can use like this:
char *string = "abcdef";
char **pointer = &string;
int i;
for (i =0; i < 4; i++)
{
printf("the next charater is %c\n", **pointer);
*pointer = *pointer + sizeof(char);
}

Resources