Questions about pointers and arrays in C [closed] - c

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have a question about this simple program in C to practice with pointers and arrays.
Code:
#include <stdio.h>
fun(int *p, int *v) {
*p++;
*(v+2) = p[3];
*v++ = p[0];
v[0] = *(p+4);
}
int main() {
int v[] = {90, 89, 8, 78, 60, 120};
int k[] = {0, 0, 0, 0, 0, 0};
int *ptr = k;
fun(v, ptr);
for (ptr = k; ptr < k + 6; ptr++)
printf("%d\n", *ptr);
}
So my question is why it prints 89 120 60 0 0 0.

It's useful to draw out (even by hand on paper!) what's going on with pointers and arrays. For the following function:
void fun(int *p, int *v) {
*p++;
*(v+2) = p[3];
*v++ = p[0];
v[0] = *(p+4);
}
You have passed these arrays:
[90] [89] [8] [78] [60] [120]
|
p
[0] [0] [0] [0] [0] [0]
|
v
What happens in fun?
*p++
This could be read one of two ways: Dereference p and (post) increment that value, or post-increment p and dereference the old value of p. Which is it? Our handy table of operator precedence says ++ comes before *, so it's the second one. Notice that we deference a pointer, but don't do anything the value. That means we could have written p++ and gotten the same result.
After the increment, our pointer has changed:
[90] [89] [8] [78] [60] [120]
|
p
The next line uses both p and v:
*(v+2) = p[3];
You can read this as "assign the 3rd value to the right of p to the 2nd spot to the right of v." The third spot to the right of p has 60, and it goes here:
[0] [0] [60] [0] [0] [0]
|
v
Next up:
*v++ = p[0];
From before, we know that *v++ means (post) increment v. The difference between ++v (pre-increment) and v++ (post-increment) is what value gets returned - in this case, we'll modify v but use its old value, assiging what p is pointing at. Notice that v has been incremented:
[89] [0] [60] [0] [0] [0]
|
v
And finally:
v[0] = *(p+4);
This can be read as "assign th e 4th value to the right of p to the 0th spot to the right of v." The forth spot to the right of p has 120, and it goes here:
[89] [120] [60] [0] [0] [0]
|
v
So at the end of the function, this is what our pointers and memory look like:
[90] [89] [8] [78] [60] [120]
| |
| p
main-v
[89] [120] [60] [0] [0] [0]
| |
| v
main-k
main-ptr

Related

How do I edit a certain char in the following? [duplicate]

This question already has answers here:
how to replace a char in char *
(3 answers)
Closed 6 years ago.
So I have the following code:
char *something = (char *) calloc(LENGTH, sizeof(char));
The length is defined as 10.
I'm imaging it like this in memory:
| [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] | [9] | \0 |
How would I change [1] without defining the whole char? And then be able to define [2], and so on...
Each change must not affect the previous change!
Thank you!
The length is defined as 10. I'm imaging it like this in memory
Incorrect. First, there are only 10 bytes (your picture shows 11) and second, all of them are filled with '\0' (which calloc() does).
How would I change [1] without defining the whole char? And then be able to define [2], and so on...
By "change" if you mean assigning values then you can index them like:
something[1] = 'a';
something[5] = 'q';
and so on.
But do remember, using it as a C-string may not work (for example, printing something using printf("%s", something);) since there are intermediate zero bytes.
Your code
char *something = (char *) calloc(LENGTH, sizeof(char));
gives you 10 (not 11) bytes, all initialised to 0.
You can change any byte in here you want
something[1] ='?';
If you use standard routine to e.g. printf this it will of course then find '0' in the first byte and interpret it as the end of a string.
Don't forget to free it when you are done
free(something);

output of p[-2] in C array [duplicate]

This question already has answers here:
What does s[-1] = 0 mean?
(6 answers)
Closed 8 years ago.
I was trying the below code snippet. Please help me in understanding how the o/p is coming as 2? What does p[-2] mean here?
int main(void){
int ary[4] = {1, 2, 3, 6};
int *p = ary + 3;
printf("%d\n", p[-2]);
}
ary is an array of four ints. This will be put in memory like this:
| 1 | 2 | 3 | 6 |
^ ^ ^
| | |
ary p - 2 p
By saying p = ary + 3, you're setting p to the address of the fourth element in the array. So, p is pointing to 6. p[-2] is equal to *(p - 2). That means you point p to the second element in the array, and access its value: 2.
int *p = ary + 3 points to ary[3] so if you move the pointer two steps back you will get ary[1]

Why can't access multidementianal arrays like single dimentional

In C
we have
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
It is stored in memory as
1 2 3 4 5 6
int A[6]={1,2,3,4,5,6};
It is also stored in memory as
1 2 3 4 5 6
we can access A[6] by A[i] where i=0,2,3..
but we cannot access B[2][3] by B[i ] where i=0,1,2..
I know there are other techniques by which we can access elements of multidimentional arrays
but we cannot access multidimentional arrays like single dimentional arrays why?
You can interpret them:
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
int* b = ( void* )B ;
for( int i = 0 ; i < 6 ; i++ )
printf("%d " , b[i] ) ;
The same goes for single arrays:
int A[6]={1,2,3,4,5,6};
int (*a)[3] ;
a = ( void* )A ;
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
printf("%d " , a[i][j] ) ;
You can access using another pointer to the array as below,
#include <stdio.h>
int main()
{
int i;
int a[2][3] = {{1,2,3}, {4,5,6}};
int *b = (int *)a;
for (i = 0; i < 6; i++)
printf("%d\n", b[i]);
return 0;
}
It has, amongst others, to do with the types of what you access.
B is a int[2][3]. That means, it has 6× the size of an int and consists of 2 successive int[3].
If you do [i], i being an integer, you get away the first level of indexing. That will give you an expression of type int[3], i. e. an array of 3 ints. That is not the same as an int and needs further indexing.
But there is another solution: dereferencing B with [0] gives you the first array. While this is limited in length, you can use it to access the whole array. So you can achieve your goal with B[0][5].
As said, B is a int[2][3], meaning that it is an array of 2 arrays of 3 ints. In memory, that looks like
offs 0 offs 1 offs 2 offs 3 offs 4 offs 5
B[0][0] B[0][1] B[0][2] B[1][0] B[1][1] B[1][2]
======================= =======================
B[0] B[1]
===============================================
B
B[0] is a 1D-array and as such degrades into a pointer as well. It points to the first element as well, but has a different type. So B[0] is of type int[2] and cannot be used as an int at the same time.
If I consider B[1], it even has a different address. See above how B[1] means the 2nd half of all data. B[0] and B[1] both have 3 times the size of an integer, meaning that the address of B[1] is 3*sizeof int positions away from B[0].
B[0] is, as said, the first array shown above. It degrades into a pointer to its first element (to B[0][0]) under most circumstances. A pointer, OTOH, can be accessed like an array: B[0][0] points to the first element, B[0][1] to the 2nd, and so on.
You are allowed to access the whole big array using this pointer, so you can go up to B[0][5]. Accessing B[0][6] is undefined behaviour in this case, meaning that you access something completely different - or even an area you aren't even allowed to read.
That is how arrays work. Making them work the way you intend to at the same time wouldn't work (how should it?).
If you want to learn more about pointers, have a look at a good C tutorial or book.

How does this recursive C code work?

There are lots of recursion questions and I basically understand some simple recursion algorithm such as sum of array elements. However, my friend gave me this code which reverses an array:
void r(int a[], int s)
{
if(s <=2 ) return;
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
r(&a[1], s-2); // this line confused me, why &a[1]
}
I know how to reverse an array using a normal for loop. But this code really confused me about recursion.
Can anyone explain the above line of code?
It is equvalent to
void r(int *arr, size_t len)
{
for ( ; len >= 2; arr+=1,len-=2 ) {
int t = arr[0];
arr[0] = arr[len-1];
arr[len-1] = t;
}
}
, where the recursive call is replaced by the loop. Ihe "increment" part of the loop (arr+=1,len-=2) is exactly the same as the parameters for the recursive call; the end condition (len >= 2) is equivalent to the recursion stopper (which was wrong in the original).
The idea behind this algorithm is at each step:
-: to swap the last a[s-1] and first a[0] elements of the array:
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
-: and to swap the middle recursively:
r(&a[1], s-2);
To understand the syntax, keep in mind that &a[n] is address of the n+1th element of the given array. If you have int *b = &a[1], then b[0] == a[1], b[1] == a[2], etc.
So:
&a[1] refers to an array starting at the second element of array a.
s - 2 means that the length of the array you pass recursively is shorter by 2 elements.
If you have an array [1 2 3 4 5 6 7 8 9 10], here's what happens as the recursion progresses:
[1 2 3 4 5 6 7 8 9 10] // r(&a[0], 10)
10 [2 3 4 5 6 7 8 9] 1 // r(&a[1], 8
10 9 [3 4 5 6 7 8] 2 1 // r(&(&a[1])[1], 6)
10 9 8 [4 5 6 7] 3 2 1 // r(&(&(&a[1])[1])[1], 4)
10 9 8 7 [5 6] 4 3 2 1 // r(&(&(&(&a[1])[1])[1])[1], 2)
Cool thing is that this analysis shows us that the terminating condtion s <= 2 is wrong: the innermost 2 elements in an even-sized array will never get swapped. It should be changed to s < 2.
Simplified Crazy walk trough;
void reverse(int a[], int s)
{
int temp; /* temporary value */
if (s <= 2) return; /* trigger done */
t = a[0]; /* temp = first index of a */
a[0] = a[s - 1]; /* a[0] = a[end - 1] (end including \0) */
a[s - 1] = t; /* a[end - 1] = temp */
r(&a[1], s - 2); /* pass address of a[1] and end - 2 */
}
Given the char array "ABCDEFG"
Simplified memory table could be:
Address Value
7 A
8 B
9 C
a D
b E
c F
d G
/* Or as used here: */
789abcd <- Simplified memory address
ABCDEFG
We get; main() calls reverse(ABCDEFG, 7)
List 1
Address ref. to A are pushed on to the stack (A{BCDEFG})
7 are pushed on to the stack
return address for caller is pushed onto the stack
etc.
function called
And something like
#::::::::::::::::::::::::::::::::::::::::::::::::::::
reverse(ABCDEFG, 7); # Push to STACK 0xB (As List 1)
#====================================================
789abcd <- Memory address.
ABCDEFG <- Values.
0123456 <- Indexes for a in recursion 1.
if (7 <= 2) return;
temp = A
+ .
a[0] = a[6] => ABCDEFG = GBCDEFG
+
a[6] = temp => GBCDEFG = GBCDEFA
reverse(BCDEFA, 5); # Push to STACK 0xC (As in List 1)
#====================================================
7 89abcd <- Memory addresses.
[G]BCDEFA <- Values
012345 <- Indexes for a in recursion 2.
if (5 <= 2) return;
temp = B
+ .
a[0] = a[4] => BCDEFA = FCDEFA
+
a[4] = temp => FCDEFA = FCDEBA
reverse(CDEBA, 3); # Push to STACK 0xD (As in List 1)
#====================================================
78 9abcd <- Memory addresses.
[GF]CDEBA <- Values.
01234 <- indexes for a in recursion 3.
if (3 <= 2) return;
temp = C
+ .
a[0] = a[2] => CDEBA = EDEBA
+
a[2] = temp => EDEBA = EDCBA
reverse(DCBA, 1); # Push to STACK 0xE (As in List 1)
#====================================================
789 abcd <- Memory addresses.
[GFE]DCBA <- Values.
0123 <- Indexes for a in recursion 4.
if (1 <= 2) return; YES!
#:::: roll back stack ::::
Pop STACK 0xE
Pop STACK 0xD
Pop STACK 0xC
Pop STACK 0xB
We are back in main() and memory region 789abcd has
been altered from ABCDEFG to GFEDCBA.
The important thing to realize is that a is a pointer to the first element of the array, so a is the same as &a[0]. &a[1] is a pointer to the second element of the array. So if you call the function with &a[1] as its argument, it works on the subarray that starts with the second element.
&a[1] is equivalent to a + 1, i.e. a pointer to the second element of the array. The function call reverses the "middle" s-2 elements of the array.
The function has to be called with:
A pointer to the first element of the array. In C it can be referenced by using the name of the array.
The size of the array.
The first 'if' checks that the array has as least two elements. Next, what the function does is to exchange the position of the first and the last element of the array.
The recursive call changes the bounds at which the next step has to work. It increments the beginning of the array by one position, and also decreases the end of the array by one position; since these two elements have been reversed in this iteration.

Trouble with array pointers in C

I was solving last years GATE question paper where i am stuck with this question
What does the following fragment of C-program print?
char c[]="GATE2011";
char *p =c;
printf ("%s", p+p[3]-p[1]);
The answer is '2011'
I am aware that in c, array variables are pointer to first address of the array. My logical answer was 'E2011', but the output is 2011
Can someone explain the pointer mathematics involved in this?
This problem has much more to do with ASCII values than it does with pointers.
p[3] == 'E' == 69 (decimal)
p[1] == 'A' == 65
p[3]-p[1] = 4
p+4 = A string starting at the 4th character.
p[] = [0] [1] [2] [3] [4] [5] [6] [7] [8]
G A T E 2 0 1 1 \0
Hence, p[4] = 2011
p[3] = A
p[1] = E
E - A = 4
hence p + 4 = address of 2
hence it prints 2011

Resources