Using the address of a pointer as a loop condition in C

118 Views Asked by At

I am trying to execute the code below:

#include <stdio.h>

int main()
{
  
    int var1 = 7;
    int* ptr1 = &var1;
    int* ptrHold = ptr1;
    int memo = 0;

    ptr1 = (int*)malloc(7*sizeof(int));

    if(ptr1==NULL){
        printf("Memory couldn't be allocated...");
        exit(0);
    }
    else{
        printf("Memory allocated for ptr1 = %d\n",7*sizeof(int));
        printf("%d",(*(&ptr1+1)-ptr1));

        for(int i=0;memo<=(*(&ptr1+1)-ptr1)/sizeof(int);i++){
        *ptr1=i;
        memo += (int)(sizeof(int));
        ptr1++;
        }
    }

    ptr1 = ptrHold;

    for(int i=0;i<5;i++){
        printf("%d \n",ptr1[i]);
    }

    free(ptr1);
    return 0;
}

But it gives me weird outputs and I think it is because of the loop condition I am using:

memo<=(*(&ptr1+1)-ptr1)/sizeof(int)

I am basically trying to subtract the value of my pointer (address of it) from the next memory location and I will have the memory it takes. After dividing it to the sizeof(int) I thought that I would get the memory allocated to the pointer in bytes and by incrementing the memo variable with the size of int, I would traverse the pointer and assign values to each block.

This individual program has no aim and I know that it is not efficient. I am not trying to create an efficient program, just trying to understand some concepts deeply. I may be making a fundamental mistake, but I am confused and I would like to understand why doesn't this code work.

My expected output was:

Memory allocated for ptr1 = 28
0
1
2
3
4
2

There are 2 best solutions below

0
ikegami On BEST ANSWER

First, I'll start with some solutions.

Expressions you could have used if you wanted to keep memo:

  • memo < 7 * sizeof( int )
  • memo < ( &ptrHold[7] - &ptrHold[0] ) * sizeof( int )
  • memo / sizeof( int ) < &ptrHold[7] - &ptrHold[0]

Expressions you could have used if you wanted to keep ptr1:

  • ptr1 < &( ptrHold[7] )
  • ptr1 < ptrHold + 7
  • ptr1 - ptrHold < 7

You have:

memo <= ( *( &ptr1 + 1 ) - ptr1 ) ) / sizeof( int )

You want the loop to end after seven passes, so you want something equivalent to

memo <= ( 7 - 1 ) * sizeof( int )

There's just no way to always get the constant ( 7 - 1 ) * sizeof( int ) from a varying ptr1. The equation is clearly wrong, and not just superficially so. The whole idea is flawed.


I am basically trying to subtract the value of my pointer (address of it) from the next memory location and I will have the memory it takes.

No, you will have 1. Pointer arithmetic works in units of the thing pointed, not in terms of bytes. That's why ptr1++; worked when you used it.

Let's look at a simple case.

uint32_t a[2];

int *p = &( a[0] );
int *q = &( a[1] );

It produces something like the following:

     int *p                  int a[2]
2000 +-----------+      1000 +-----------+
     | 1000    -------->     |           |
     +-----------+      1004 +-----------+
                    +-->     |           |
                    |        +-----------+
     int *q         |
3000 +-----------+  |  
     | 1004    -----+
     +-----------+     

The addresses might be 4 bytes apart.

printf( "%p\n", (void *)p );  // 0x1000
printf( "%p\n", (void *)q );  // 0x1004

But the differences between the pointers is one.

printf( "%td\n", p - q );     // 1

It's easy to show that's always the case.

   &( a[1] ) - &( a[0] )               // Two adjacent array elements.
≡  &( *( a + 1 ) ) - &( *( a + 0 ) )   // `x[y]` ≡ `*( x + y )` by definition.
≡  ( a + 1 ) - ( a + 0 )
≡  a + 1 - a - 0
≡  1

Similarly, &ptrHold[7] - &ptrHold[0] is equal to 7.

3
saintMath On

It's very good that you are trying to understand the concepts of pointers deeply. This is an essential part of C/C++ and you will need it moving forward.

In order to give you more insight into this, I have changed your code, especially the loop condition, and added more printf statements and comments with the values printed on my PC.

Please run this code, check the values you obtain (they will be different than the ones I saw) and read the comments I have added. I hope they bring some additional clarifications.

I apologise in advance if you already know some of these things.

#include <stdio.h>
#include <stdlib.h>

int pointers()
{
    int var1 = 7;
    int* ptr1 = &var1;
    int* ptrHold = ptr1;
    int memo = 0;

    printf("&var1 is:%p \n", &var1);          //0041FB78
    printf("ptr1 is:%p \n", ptr1);            //0041FB78 because of the assignment ptr1 = &var1
    printf("&ptr1 is:%p \n", &ptr1);          //0041FB6C ptr is located at a lower mem adress than var
    printf("ptrHold is:%p \n", ptrHold);      //0041FB78 because of assignment ptrHold = ptr1
    printf("&ptrHold is:%p \n", &ptrHold);    //0041FB74 ptrHold is located at a higher address than ptr1

    /*
    | variable name  | memory address | value in memory |
    | ptr1           | 0041FB6C       | 0041FB78        |
    | ptrHold        | 0041FB74       | 0041FB78        |
    | var            | 0041FB78       | 00000007        |
    */

    /*
    NOTE: There is one more caveat with the 'values in memory' above; that is not a true to life representation.
    For example for var, the bytes are actually:
    | var            | 0041FB78       | 07        |
    |                | 0041FB79       | 00        |
    |                | 0041FB7A       | 00        |
    |                | 0041FB7B       | 00        |

    */
    unsigned char* bytes = (unsigned char*)&var1;
    printf("bytes[0]=%d \n", bytes[0]); //bytes[0]=7
    printf("bytes[1]=%d \n", bytes[1]); //bytes[0]=0
    printf("bytes[2]=%d \n", bytes[2]); //bytes[0]=0
    printf("bytes[3]=%d \n", bytes[3]); //bytes[0]=0

    var1 = 0x10203040;
    printf("bytes[0]=%x \n", bytes[0]); //bytes[0]=40
    printf("bytes[1]=%x \n", bytes[1]); //bytes[1]=30
    printf("bytes[2]=%x \n", bytes[2]); //bytes[2]=20
    printf("bytes[3]=%x \n", bytes[3]); //bytes[3]=10


    ptr1 = (int*)malloc(7 * sizeof(int));

    if (ptr1 == NULL) {
        printf("Memory couldn't be allocated...");
        exit(0);
    }
    else {
        printf("Memory allocated for ptr1 = %d\n", 7 * sizeof(int)); //Memory allocated for ptr1 = 28

        printf("ptr1 is:%p \n", ptr1);         //0088A2E0 the value of ptr1 is different because of malloc
        printf("&ptr1 is:%p \n", &ptr1);       //0041FB6C the adress of pt1 did not change; is the same as above

        printf("&ptr1[0] is:%p \n", &ptr1[0]); //0088A2E0 the addrees of the first element is equal to the value stored in ptr1 
        printf("&ptr1[1] is:%p \n", &ptr1[1]); //0088A2E4 the adress of the second element is equal to the value of ptr1 + 4 (sizeof *int is 4)

        printf("&ptr1 + 1 is:%p \n", &ptr1 + 1);
        printf("*(&ptr1 + 1) is:%p \n", *(&ptr1 + 1));

        int* iter = ptr1;
        for (int i = 0; iter <= &ptr1[6]; i++) { //a similar condition is: iter < ptr1 + 7
            *iter = i;
            memo += (int)(sizeof(int));
            iter++;
        }
    }

    //ptr1 = ptrHold; This is bad: ptrHold is pointing to address of var1; there is only 1 int at that address
    //trying to print 5 ints starting from that adress can be done but it will print garbage and is undefined behavior

    for (int i = 0; i < 5; i++) {
        printf("%d \n", ptr1[i]);
    }

    free(ptr1);
    return 0;
}