Trouble understanding the value of a double pointer in C - c

I couldn't understand the first and second value of the output, why are they different ? What is the second output meaning here ?
The Code is:
int **p = (int **)malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++) {
p[i] = (int *)malloc(sizeof(int) * 2);
}
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
p[i][j] = c++;
}
}
printf("%d %d %d %d\n", (int)&p[0][0], (int)p, (int)*p, **p);
Output: 34439216 34439184 34439216 1

Alright. Let's talk about some basic issues first:
On many systems, int will take up less room than void *. So you're possibly truncating your pointers when you print them. It's quite easy to fix that, so let's do it.
Additionally, it's unnecessary to cast the value of malloc(), so let's get rid of that as well to clean up the code a bit.
Finally, as chris notes, to use the %p format specifier, we need to cast the int ** and int * variables to void *.
Fixed foo.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int **p = malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++)
p[i] = malloc(sizeof(int) * 2);
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
p[i][j] = c++;
printf("%p %p %p %d\n", (void *) &p[0][0], (void *) p, (void *) *p, **p);
}
Which now outputs:
0x7fd193c03930 0x7fd193c03920 0x7fd193c03930 1
So now, your actual question:
First, let's talk about what address &p[0][0] points to. That's a fairly complicated expression, but we can reduce it using a fairly simple process such that we end up with *p or p[0].
&p[0][0] == &*(p[0] + 0) == p[0] + 0 == p[0] == *(p + 0) == *p
Looking at that, it should be pretty clear why &p[0][0] (the first argument) and *p (the third argument) print the same value.
Now, I don't see any good reason why p[0] should point to the same address as p. p and p[0] have been assigned values from separate calls to malloc().

Related

Is it OK to pass (double ***) pointers using (void **)?

I compile the code below with gcc using -Wall -Werror and it compiles cleanly, runs as expected; however, I'm just curious if it is OK, in ANSI and/or ISO C context, to pass a (double ***) pointer via (void **).
The ISO/IEC 9899:2017, section 6.6 - 9 says:
"The array-subscript [] and member-access . and -> operators,
the address & and indirection * unary operators, and pointer
casts may be used in the creation of an address constant, but the
value of an object shall not be accessed by use of these operators."
In connection to this recommendation, the function allocateMatrix is, in fact, supposed to just allocate memory and return the corresponding address; so, please disregard the inner loop that assign values, it's there for test purposes only.
void allocateMatrix(int n, void **a) {
int i = 0, j = 0;
double **pTmp = calloc(n, sizeof(double *));
for (i = 0; i < n; i++) {
pTmp[i] = malloc(n * sizeof(double));
// following loop is inserted to make sure code runs as expected
// this does not exists in real code
for (j = 0; j < n; j++) {
pTmp[i][j] = (double)(i + 1) + (double)(j + 1) / 10.0f;
}
}
*a = pTmp;
return;
}
int main(int argc, char const *argv[]) {
int i = 0, j = 0;
int n = 5;
double **a = NULL;
// "a" is a (double **) pointer; so, "&a" is now a (double ***) pointer
allocateMatrix(n, (void **)&a);
// testing...
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
printf("%6.2lf", a[i][j]);
}
printf("\n");
}
return 0;
}
The C standard allows for conversion to and from void *, however that lattitute does not exist for void **.
Change the function argument to void * and cast it appropriately and it will work.
void allocateMatrix(int n, void *a) {
...
*(double ***)a = pTmp;
}
And change remove the cast from the function call:
allocateMatrix(n, &a);

Incorrect first value in array of pointers

The dynamicRandomMatrix function should return a pointer to an array of n pointers each of which points to an array of n random integers.
I got it to print mostly correct, except the first number in the array. This is the output:
n=3: -2084546528, 59, 45
Can anyone help me figure out why the first number in the array is so small? I think it must be something to do with local variables and access or something, but I am not sure.
int** dynamicRandomMatrix(int n){
int **ptr;
ptr = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
int *address = randomArray(n);
ptr[i] = address;
}
return ptr;
free (ptr);
}
int* randomArray(int n){
int *arr;
arr = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
int num = (rand() % (100 - 1 + 1)) + 1;
arr[i] = num;
}
return arr;
free(arr);
}
int main(){
int **ptr;
int i;
ptr = dynamicRandomMatrix(3);
printf("n=3: ");
for (i = 0; i < 3; i++) {
printf("%d, ", *ptr[i]);
}
return 0;
}
In your code,
ptr = malloc(sizeof(int) * n);
is not correct, each element in ptr array is expected to point to a int *, so it should be ptr = malloc(sizeof(int*) * n);. To avoid this, you can use the form:
ptr = malloc(sizeof(*ptr) * n);
That said, all your free(array); and free (ptr); are dead code, as upon encountering an unconditional return statement, code flow (execution) returns to the caller, and no further execution in that block (function) takes place. Your compiler should have warned about this issue. If not, use proper flags to enbale all warnings in your compiler settings.

Debugging Pointers with Malloc and Free

Consider the code below:
#include < stdio.h >
#include < stdlib.h >
#define SIZE 10
int main() {
int * p, i;
p = malloc(SIZE * sizeof(int));
if (p == NULL) {
printf("malloc failed.\n");
return 1;
}
for (i = 0; i < SIZE; i++)
* (p + i) = i * i;
for (i = 0; i < SIZE; i++)
printf("%d\n", * p++);
free(p);
return 0;
}
This code doesn't work. However I am not sure why. My professor gave an explanation that doesn't make much sense to me. Supposedly the free function doesn't work.
From what I understand, you can only free pointers that were created using malloc. And here we modify that pointer before sending it to free, thereby making our statement invalid.
Is this the correct way to critique that code?
And here we modify that pointer before sending it to free, thereby making our statement invalid.
Is this the correct way to critique that code?
Yes, code is not freeing the original pointer allocated due to p++ which increments the pointer with each loop iteration.
Instead, print in such a way p is not changed.
for (i = 0; i < SIZE; i++) {
// printf("%d\n", * p++);
printf("%d\n", p[i]);
// or
printf("%d\n", * (p + i));
}
// With above change, `p` is the same as the original allocated value.
free(p);

C program printing garbage values

I am trying to create an array and assign values to it. While I am able to assign values correctly, I am unable to retrieve those values and I have no idea why.
Here is a part of the code snippet.
void *arr = (void *)(malloc(sizeof(void *) * 5));
int i = 0;
for(i = 0; i < 5; i++) {
*(int *)(arr+i) = initial[i];
printf("Value of array: %d\n", *(int *)(arr+i));
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *(int *)(arr+i));
DArray_push(result, (arr+i));
}
The output of the program is
Value of array: 4
Value of array: 1
Value of array: 3
Value of array: 2
Value of array: 0
Pushing: 33751300
Pushing: 131841
Pushing: 515
Pushing: 2
Pushing: 0
Why is my program able to accept values correctly, but is printing out garbage values when I try to retrieve them later?
Turn warnings on. (arr+i) is not defined (you cannot add to a void pointer and you do the cast only after this addition). You see undefined behavior.
You further allocate things the size of a pointer but treat it as int (more undefined behavior).
Why not write:
int *arr = malloc(sizeof(int) * 5);
int i = 0;
for(i = 0; i < 5; i++) {
arr[i] = initial[i];
printf("Value of array: %d\n", arr[i]);
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", arr[i]);
}
Pushing: 33751300 = 4 + 1 * 256 + 3 * 256 * 256 + 2 * 256 * 256 * 256
Pushing: 131841 = 1 + 3 * 256 + 2 * 256 * 256
Pushing: 515 = 3 + 2 * 256
Pushing: 2
Pushing: 0
That part is already wrong, but would on most 32 or 64 bit compilers still work: sizeof(void *). Only because this this at least the size of an int on these platforms though.
*(int *)(arr+i)
This is the actual problem. This did not access the next integer, it accessed the next address addressable by a void pointer, which is typically a single byte. Accessing the next integer would had been equivalent to this:
*(int *)(arr + i*sizeof(int))
Or easier to read:
*( ((int *)arr) + i)
Remember, incrementing a pointer by an offset doesn't add to the raw memory address, but it depends on the pointer type.
The point here is the arithmetic of pointers. When we're adding a value by 1, it wouldn't be the same for different type pointers. So let's check an example:
(int *)p + 1 // it's moving 4 bytes
(void *)p + 1 // it's moving 1 byte in my compiler, void * is a generic type
In your example we know we're working with integers, so we need to tell the compiler to convert the generic pointer to the appropriate type before we do any operations with.
Try to execute the following code to understand what I'm gonna talking about:
#include <stdio.h>
#include <stdlib.h>
void main() {
int initial[] = {100, 101, 102, 103, 104};
void *arr = (void *)(malloc(sizeof(void *) * 5));
int i = 0;
for (i = 0; i < 5; i++) {
printf("%p\t%p\n", arr + i, ((int *)arr) + i);
}
for(i = 0; i < 5; i++) {
*(((int *)arr)+i) = initial[i];
printf("Value of array: %d\n", *(((int *)arr)+i));
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *(((int *)arr)+i));
}
}
I found some resources to help:
https://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html
https://www.viva64.com/en/t/0005/
The thing is that you don't reset your arr pointer. Thus in your second loop you actually print the values after the initial array.
You need to create a variable to traverse your array.
void *p = arr;
And then use it to traverse the array. And again before the second loop.
Moreover, do not cast the return value of a malloc function call (even when you are casting it to a void pointer which is the actual return type of malloc).
EDIT: you actually don't change the value of arr. My bad.
First of all, the thing with casting malloc to void and using sizeof void is totally pointeless.
Assuming initial[]is another array, the fix would be:
#include <stdio.h>
#include <stdlib.h>
int initial[] = {10, 20, 30, 40, 50};
int main()
{
//allocate memory for 5 integers
int* arr = malloc(sizeof(int) * 5);
//loop over and copy from inital to arr
int i = 0;
for(i = 0; i < 5; i++) {
arr[i] = initial[i];
printf("Value of array: %d\n", arr[i]);
}
//pointer to first element of arr
int* arrPointer = arr;
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *arrPointer);
//DArray_push(result, (*arrPointer));
//increment the arrPointer
arrPointer++;
}
//reset pointer if needed later...
arrPointer = arr;
return 0;
}

Realloc error in C

I've just started C read the man page but could not find the proper answer. So the code is below
void *p = malloc(10*sizeof(int));
int *q = p;
int NUMOFINT = 10;
for (int i = 0; i < NUMOFINT; i++){
printf("%i ", q[i]);
}
void *realloc(void *p, 20*sizeof(int));
for (int i = 0; i < 21; i++){
printf("%i ", q[i]);
and it is giving this error:
malloc.c: In function ‘main’:
malloc.c:31:24: error: expected declaration specifiers or ‘...’ before numeric constant
I did not quite understand that the size format was ok for malloc() but not ok for realloc. So how do I correct the error?
Edit:
so when I make it as:
void *morep = realloc(p, 20*sizeof(int));
int *q2 = morep;
for (int i = 0; i < 20; i++){
printf("%i ", q2[i]);
}
it prints out q2[11] as 135121
This
void *realloc(void *p, 20*sizeof(int));
is wrong. You want
p = realloc(p, 20*sizeof(int));
Incidentally, this line is also a problem (but will compile fine):
for (int i = 0; i < 21; i++){
You allocated p to 20*sizeof(int) bytes, so element 20 is past the end of the array. You want:
for (int i = 0; i < 20; i++){
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int *temp; /* To use with realloc, it's more secure */
void *p = malloc(10*sizeof(int));
int *q = p;
int NUMOFINT = 10;
/* dont forget to compile with -std=99 flag, if you use this kind of for loop */
for (int i = 0; i < NUMOFINT; i++){
printf("%i ", q[i]);
}
printf("\n");
/* It's more secure to use this kind of realloc */
temp = realloc (p, 20 * sizeof(int) );
if (temp == NULL)
{
fprintf(stderr,"Reallocation failed --> %s\n", strerror(errno));
free(p);
exit(EXIT_FAILURE);
}
else
{
p = temp;
}
/* Zeroing after realloc */
for (int i = NUMOFINT; i < 21; i++)
q[i] = 0;
for (int i = 0; i < 21; i++)
{
printf("%i ", q[i]);
}
printf("\n");
return 0;
}
realloc can tries to expand the existing memory block in heap, if its not possible it will allocate a new separate block of memory for the new size and it will copy the data from old memory block to the new memory block also.
So if realloc returns the address same as p then it just expands the old memory block. Or else we have to free the old memory block and start using the new memory block returned by realloc.
#define NUMOFINT 10
#define NUMOFINT_NEW 20
void *p = malloc(NUMOFINT * sizeof(int));
int *q = p;
void *temp = NULL;
for (int i = 0; i < NUMOFINT; i++)
{
printf("%i ", q[i]);
}
temp = realloc(p, NUMOFINT_NEW * sizeof(int));
if (temp == NULL)
{
exit(0);
}
else if (temp != p)
{
free(p);
p = temp;
}
//else temp is equal to p
for (int i = 0; i < NUMOFINT_NEW; i++)
{
printf("%i ", q[i]);
}
Here q[0] to q[9] will have the values(0, 1, 2..9) assigned, and the rest (q[10] to q[19]) will have garbage value. We have not memset the newly allocated memory to 0 also.
you can memset also before for loop,
memset((q + NUMOFINT), 0, (NUMOFINT_NEW - NUMOFINT));
Mistakes in your program are
1) compilation error because
void *realloc(void *p, 20*sizeof(int)); This statement doesn;t looks like a function call.
2) for (int i = 0; i < 21; i++) - After memory is realloced to 20 elements, you can access only upto 19th, accessing 20th may leads to crash(undefined behaviour).
3) it prints out q2[11] as 135121 - Newly reallocated memory is neither memset to 0 nor assigned any meaningful values.

Resources