Use of &ampersand and square bracket in printf - c

I came across the following code in an MCQ quiz,
#include <stdio.h>
int main()
{
int j =2, k =4;
printf(&j["Programming"], &k["Theory"]);
k = j ^ 3;
if (k == j)
printf(&k["Practical"], "Trytosolve");
else
printf(&j["Problem creation"]);
return 0;
}
where ampersand is used in the beginning itself and outside the quotes ("") of printf statement. I am only aware of the traditional use of printf statement and its format specifiers.
I tried to run this code, and it showed no error but this warning:
format not a string literal and no format arguments
and the following output
ogrammingoblem creation (this was one of the options in multiple choices)
I tried to search for such use, but could not find. Can someone explain this use of & and square brackets?

Say we have an array a and a variable i of integral type, then a[i] is equivalent to *(a + i), i.e. we can obtain the ith element of a by decaying a into a pointer to its first element, incrementing that pointer by i and dereferencing the result. This it true because arrays occupy contiguous addresses in memory.
Now, as it turns out, i[a] is also equivalent to a[i], this is more of a "trick" that nobody (to my knowledge) would ever use in production. It's sort of intuitively justifiable that this would be the case because a[i] == *(a + i) == *(i + a) == i[a].
So then, &j["Programming"] == &(*(j + "Programming")). And because dereferencing a pointer and then taking it's address is a noop, this is j + "Programming" == "Programming" + j == "ogramming", because strings are just arrays of characters.
Same for the other branch, which is executed because 2 ^ 3 == 1 != 2.

Maybe this example program will show you the math behind the scenes:
#include <stdio.h>
int main(void)
{
int j=2, k=4;
char *p1 = "Programming";
// Print the address of j
printf("&j = %p\n", &j);
printf("\n");
printf("Pointer arithmetic\n");
// Print the address of "Programming"
printf("p1 = %p\n", p1);
// Print the value of j
printf("j = %8d\n", j);
// Print the result of the pointer computation
printf("&j[\"%s\"] = %p\n", p1, &j[p1]);
// Print the result of the equivalent pointer computation
printf("p1 + j = %p\n", p1 + j);
printf("\n");
printf("Print strings\n");
// Print "Programming" after skipping the first two letters
printf("&j[\"%s\"] = %s\n", p1, &j[p1]);
// Print "Programming" after skipping the first two letters
printf("p1 + j = %s\n", p1 + j);
return 0;
}
Output
&j = 0x7fffb3325aa8
Pointer arithmetic
p1 = 0x4006e4
j = 2
&j["Programming"] = 0x4006e6
p1 + j = 0x4006e6
Print strings
&j["Programming"] = ogramming
p1 + j = ogramming

Related

Pointers to an Array In C

So my book is explaining me pointers to an array using ts example
#include <stdio.h>
int main()
{
int s[4][2] = {
{1234,56},{1212,33},{1434,80},{1312,78}
};
int(*p)[2];
int i, j, * pint;
for (i = 0; i <= 3; i++)
{
p = &s[i];
pint = (int*)p;
printf("\n");
for (j = 0; j<= 1; j++)
{
printf("%d ", *(pint + j));
}
}
return 0;
}
The output is Given as
1234 56
1212 33
1434 80
1312 78
No issue I am getting the same output.
My question is what was the need of using another pointer pint ?
Why can't we directly use P?
So When I tried to do it using P directly it didn't work
printf("%d ", *(p + j));
I got garbage values in output, Why is this happening?
I also tried printing p and pint they are the same.
Although p and pint have the same value, p + 1 and pint + 1 do not. p + 1 is the same as (char *)p + sizeof *p, and pint + 1 is the same as (char *)pint + sizeof *pint. Since the size of the object pointed to is different, the arithmetic gives different results.
The pointer p is declared like
int(*p)[2];
So dereferencing the pointer expression with the pointer in this call of printf
printf("%d ", *(p + j));
you will get the j-th "row" of the type int[2] of the two dimensional array that in turn will be implicitly converted to a pointer of the type int * that will point to the first element of the j-th "row".
So instead of outputting elements of each row you will output first elements of each row that moreover results in undefined behavior when i will be greater than 2.

Values are not getting assigned to continuous addresses

Why on compiling the below piece of code is giving runtime error?
#include<stdio.h>
int main()
{
int i;
int *p;
int a = 10;
p= &a;
printf("address of a = %x\n",p);
*(p + 0) = 5;
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
for(i=0; i < 4; i++)
{
printf("address = %x value = %x\n",(p+i),*(p+i));
}
return 0;
}
In this code i am assigning values to the address of variable named a after that starting from address of a the values (6,7,8) respectively are getting assigned to the next address of a consecutively.
*(p + 1) = 6;
p is an int* - meaning that when you increment it by one, it doesn't jump one byte forwards - it jumps sizeof(int) bytes forward (probably 4 bytes). If you want to assign to the bytes separately, cast the pointer to a char*:
*((char*)p + 1) = 6;
When you write code like *(p + 1) = 6; - your program is very likely to crash. Per the standard this is undefined behavior, in practice what usually really happens behind the scenes is that since p == &a and a is on the stack, p + 1 points to 4 bytes in the stack above a - which likely contains some random value like a stack canary or a return address - and you are corrupting this value.
These expressions:
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
Create pointers that are past the memory bounds of a which are then subsequently dereferenced. Reading memory past the bounds of an object (or even attempting to create such a pointer if it is not just past the object) triggers undefined behavior.
In this particular case it caused your program to crash, but there is no guarantee that will happen.
You should allocate that memory before accessing it. Try using malloc().
Your code should look like this:
#include<stdio.h>
int main()
{
int i;
int a = 10;
char *p= (char *)&a;
printf("address of a = %p\n",p);
for (i = 0; i < sizeof(a); ++i) {
*(p + i) = i + 5;
}
for(i = 0; i < sizeof(a); ++i) {
printf("address = %p value = %d\n", p + i, *(p + i));
}
return 0;
}
One solution is to define p as a pointer to char. Another approach is, as suggested in other answers, just cast p into a pointer to char before any arithmetic. When using pointer arithmetic, the number of bytes you "jump" is as the size of the pointed type. So, p + 1 will jump 4 bytes, in case int is 4 bytes. This is why you should use a pointer to char if you want to move one byte at a time.
In addition, your loops should run N times, where N in the number of bytes. So, my suggestion is to use sizeof.
Last thing, please note that in order to print an int you should use %d, and use %p to print pointers (i.e addresses).

Understanding double pointer to an array in C

I have been learning C for couple of months and I came across a question which is given below.
#include <stdio.h>
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a;
for (int i=0; i<2; ++i) {
for (int j=0; j<2; ++j) {
printf("%d %u\n", a[i][j], (*(a+i) + j));
}
}
for (int i=0; i<4; ++i) {
printf("%d %u\n", *(*p + i), (*p + i));
}
printf("%u\n", p);
printf("%u\n", p+1);
printf("%u\n", p+2);
printf("%u\n", p+3);
printf("%u\n", *p);
printf("%u\n", *p+1);
printf("%u\n", *p+2);
printf("%u\n", *p+3);
puts("");
}
The output that I am getting on my machine is as follows:
1 3751802992
2 3751802996
3 3751803000
4 3751803004
1 1
9 9
17 17
25 25
3751802992
3751803000
3751803008
3751803016
1
9
17
25
I understand the first four lines of the output where the elements of the 2D array and their respective addresses is getting printed but I have absolutely no clue how the other outputs are happening.
I checked in an online IDE and there also I am getting the same output except the addresses which obviously will differ.
I know that int (**p)[2] is incomparable pointer type to a[2][2] which is a (int *)[2] data type.
But still I want to understand how the p pointer is working.
Can someone please help me understand how this is happening?
I have been eagerly waiting to get the logic behind the code outputs.
I am extremely sorry for the long code snippet and the long output sequence.
Thanks in advance.
N.B - I know that the code is producing a lot of warnings but I want to get the core idea about p.
The problem with this code starts right here:
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a; // <-- Invalid conversion, undefined behaviour
// warning: incompatible pointer types initializing 'int (**)[2]' with an expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
// ... Everything past here is undefined behaviour
}
There's a huge difference between int** and what you're attempting to cast, one big enough that this conversion isn't possible.
int** means, specifically, a structure where it's an array of int*, or pointers. Treating int[2] as a pointer is going to be a mess. That any of this code even semi-works is hard to explain. It's the compiler trying to make the best of a bad situation.
I introduced a macro LEN to calculate your array sizes instead of hard-coping the magic numbers, fixed the declaration of p, changed the unsigned format %u to signed %d as you were printed signed values, the last loop, I am sure what the 2nd thing you were trying to print so left it out, and the last section of print statements were pointers so used %p for those in a loop instead of duplicating the code:
#include <stdio.h>
#define LEN(a) sizeof(a) / sizeof(*a)
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (*p)[2] = a;
for (int i=0; i < LEN(a); i++) {
for (int j = 0; j < LEN(*a); j++) {
printf("%d %d\n", a[i][j], *(*(a + i) + j));
}
}
for (int i=0; i < LEN(a) * LEN(*a); i++) {
printf("%d\n", *(*p + i));
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", p + i);
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", (void *) *(p + i));
}
puts("");
}
This is a problem:
int (**p)[2] = &a; // int (**)[2] = int (*)[2][2]
The type of &a is int (*)[2][2], not int (**)[2]. Your pointer declaration should be
int (*p)[2][2] = &a;
Unless it is the operand of the sizeof or unary & operators or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T will be converted, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
The expression a "decays" from type "2-element array of 2-element array of int" (int [2][2]) to "pointer to 2-element array of int" (int (*)[2]). However, since a is the operand of the unary & operator that conversion doesn’t take place, so &a has type "pointer to 2-element array of 2-element array of int" (int (*)[2][2]). Thus,
p == &a
(*p) == a
(*p) + i == a + i == &(*p)[i] == &a[i]
*((*p) + i) == *(a + i) == (*p)[i] == a[i]
*((*p) + i) + j == *(a + i) + j == &(*p)[i][j] == &a[i][j]
*(*((*p) + i) + j) == *(*(a + i) + j) == (*p)[i][j] == a[i][j]
A pointer is used to store the address of variables. So, when we define a pointer to pointer, the first pointer is used to store the address of the second pointer. Thus it is known as double pointers.
EXAMPLE:
int main() {
int integerValue = 84;
int *pointer1;
int **pointer2;
pointer1 = &integerValue;
pointer2= &pointer1;
printf("Value of integer = %d\n", integerValue);
printf("Value of integer using single pointer = %d\n", *pointer1);
printf("Value of integer using double pointer = %d\n", **pointer2);
return 0;
}
OUTPUT:
Value of integer = 84
Value of integer using single pointer = 84
Value of integer using double pointer = 84

Printing value of a pointer to a pointer

I am trying to wrap my head around "pointer to a pointer". And I tried some experiments and I got stuck here for a while:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
}
And I got this as output:
printing
Source: 4
Output by pointer: 4, 4
Output by pointer to a pointer: 4, 4
printing
Source: 5
Output by pointer: 5, 5
I don't understand why after 1 loop, the program stop at the 2nd loop- line 9. Did I misunderstand anything basic knowledge or something else.
Thank you for reading.
Change the last printf to:
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
You're basically using *pp in place of p, but the * operator doesn't group as tightly as [] so you need to use parentheses in the first form. In the second form, you need to dereference pp before adding i, after which the result is dereferenced.
For starters it is unclear why there is used the magic number 4 in the loop instead of the number 5 that is the number of elements in the array
for ( int i = 0; i < 4; i ++)
^^^^^
The pointer pp does not point to first element of an array. It points to a single object
int **pp = &p;
So these expressions
*pp[i] (that is equivalent to *(pp[i] )
and
**(pp + i)
does not make sense.
An expression using the pointer p can be written using the pointer pp like *pp.
So these correct expressions
p[i]
and
*(p + i)
can be written using the pointer pp the following way (just substitute p for *pp taking into account operation precedences)
( *pp )[i]
and
*( *pp + i )
You acesses to pointer thru pointer-to-pointers are wrong:
you must access the pointee as the array:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
}
This line is wrong
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
You need to change it to
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
so that you dereference the double pointer before using it as a normal pointer.
You can think of it like this:
p is the same as (*pp)
In other words - in a valid expression that uses p you are allowed to substitute p with (*pp). That is
p[i] --> (*p)[i]
*(p + i) --> *((*pp) + i) --> *(*pp + i)
Notice that the parenthesis is important. The parenthesis can be removed in the second example but not in the first as [] has higher precedence than *.
Doing pp + i generates a pointer that doesn't point to any valid object. So when you dereference it using **(pp + i) you do an illegal access an your program crashes.

C Programming Pointers

I don't understand why is the last code block generating 1819043176 1870078063 6581362 0 1 2 3 4 0 6488159... These numbers are not random, but why those numbers? Thank you!
int main(void) {
int x;
int y[10];
int* p;
char* q;
int k;
char* prefix;
k = 0;
while (k < 10) {
y[k] = k;
k = k + 1;
}
x = 42;
printf("address of y are %d %d %d\n", y, y + 1, y + 9);
doit(y + 1);
p = &y[0];
printf("p is %d\n", p);
*p = 42;
p = p + 9;
printf("p is %d\n", p);
*p = 17;
q = "hello world";
p = "hello world";
k = 0;
while (k < 10) {
printf("%d ", q[k]);
k = k + 1;
}
printf("The end\n");
k = 0;
while (k < 10) {
printf("%d ", p[k]);
k = k + 1;
}
printf("The end\n");
}
doit
void doit(int p[9])
{
char* prefix = "";
int k = 0;
printf("p is %d at address %d\n", p, &p);
while (k < 10)
{
printf("%s%d", prefix, *p);
prefix = ", ";
k = k + 1;
p = p + 1;
}
printf("\n");
}
1819043176 is 6C6C6568 in hexadecimal, which is stored as the bytes 68, 65, 6c, 6c on a little-endian machine. These are the first four characters of "hello world". And so on.
Normally you are not supposed to do these things in C, the results are undefined or implementation-dependent.
If you nevertheless want to peek around in memory then better do it in a more systematical way, for example write a small utility to do a hex dump.
I'm not digging enough to give you the answer, but I do have an important suggestion: crank up your compiler's warnings. When my bash starts up, it aliases gcc to /usr/bin/gcc -Wall -Wextra -Werror so that anything I try to compile has to pass through some of GCC's harshest tests (and it treats all warnings as errors, so minor mistakes won't compile). Your code gave me an error printout a mile long (not literally). Some errors:
printf() has a special format specifier for pointers: %p. Don't use %d - that's for ints.
p is an int * (pointer to an int), "hello world" is a char *. You can assign one to another, but it's usually a bad idea, so if you really want to do it, you should use a cast to say "Hey, I meant to do this:" p = (int *) "hello world";
main() doesn't return void, it returns an int. You know this, because you declared int main(void) like a good programmer, but then we get to the end of main() and there's no return statement! How is it supposed to return an int if you don't return anything? In C++, we can skip the ending return statement, but not in C (at least, we really shouldn't, because bad things can happen).
Also, you have a pattern that you repeat often:
k = 0;
while (k < 10) {
y[k] = k;
k = k + 1;
}
Welcome to for loops:
for(k = 0; k < 10; k++) {
y[k] = k;
}
for() loops have three parts:
for(init; cond; inc)
init is run once before the loop, then the loop executes as long as cond is true, executing inc at the end of every loop. It is almost exactly equivalent to what you're doing, and is more concise.
you have p pointing to the string "hello world"
but you have defined p as a pointer to integers, so p looks like this
p[0] = 'hell'
p[1] = 'o wo'
p[2] = 'rldx'
p[3] = 'xxxx'
p[4] = 'xxxx'
p[5] = 'xxxx'
p[6] = 'xxxx'
p[7] = 'xxxx'
p[8] = 'xxxx'
p[9] = 'xxxx'
where xxxx means you have not set this memory to anything.
lets look at p[0]
h=0x68
e=0x65
l=0x6c
l=0x6c
so you have the hexidecimal number 0x6c6c6568 which you can check is 1819043176
and so on
The reason that (a) you're getting numbers printed and (b) that the numbers aren't random is because in the last code block, you're trying to print a string as decimals. After all, that's what %d expects to print - a decimal. That's not got anything to do with pointers.
You don't say what output you're expecting, but you have to chose the correct formatter to do that.
Another suggestion - the normal idiom for incrementing a variable in C and C++ is
++x;
or
x++;
to increment a value by 1 and
x += 9;
to increment it by more than 1 (obviously 9 in this case).
I think it's because you are passing a char to printf when the format string is expecting an integer. Try casting q[k] and p[k] to integers.
while (k < 10) {
printf("%d ", (int)p[k]);
k = k + 1;
}
The call to printf() is not a normal function call, it uses varargs/stdargs and in those, the function needs to unpack the correct type.
So the first number in your output, 1819043176, corresponds to 0x6C6C6568. See how the character value for the lowercase 'h' (0x68) that you were presumably expecting to see is the least significant byte in four-byte integer? This is because the varargs routines were expecting an integer-sized argument because of the %d format specifier.
This doesn't do what you think it does (I hope, maybe):
while (k < 10) {
printf("%d ", q[k]);
k = k + 1;
}
Think about what q is, what printf does, and what %d means (hint, look at the assignment of q). I would also suggest including the output of what you expect as a result because it's not obvious from the code what you're actually trying to accomplish (other than printing out pointers to ints using printf instead of ints).
Your problem is about the variable p.
it is int *, and sizeof an integer variable is 4 byte (it may change according to system and compiler) but the sizeof (char) is 1 byte
"hello world" string is 12 byte -with null-
12 byte can be defined in 3 integer.
after this line
p = "hello world";
only 3*4 memory of p will be used. (*p points array "y")
Rest of them will be null...

Resources