0

I am trying to learn better how pointer work in C and pointer to pointer to structure things broke my mind. Here I have 3 questions:

  1. If I have a structure and a pointer to pointer **tests to this structure (so this is something like an array) how can I use p to access to array members (the best way)? tests[i]->id fails (example of source is below)
  2. Having that monstrous line with pointers below is something bad to have in the code but I would like to do work with it as well. I think I've mistaken with its template, the output for every next structure's address looks like jumps 32 bytes ahead, while size of structure is only 4 bytes. So in the line I want to (1) take the initial address of the tests top pointer, (2) add to it size of the structure TestCase multiplied by i so it points to correct array element and (3) add offset of the id field of the structure. And after that I will get address where I can write the id value in memory, right? Am I doing this correct?
  3. Why *tests value was changed? Buffer overflow?

    struct TestCase{
        int id;
    };
    int main()
    {
        TestCase ** tests;
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        *tests = (TestCase*)malloc(sizeof(TestCase*)*5);
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            //*(int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) = i;
    
            int addr = tests; // address of structures array in memmory;
            addr += sizeof(TestCase)*i; //address of current structure;
            addr += (int)&(((struct TestCase*)NULL)->id); // Adding id parameter offset in memory to current address
            *(int*)addr = i; // setting id for current structure equal to i
            cout << (int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) << endl;
        }
        cout << "*tests = " << *tests << endl;
        return 0;
    }
    

    Output is:

    Size of TestCase: 4
    *tests = 0x600048600
    0x23ab90
    0x23abb0
    0x23abd0
    0x23abf0
    0x23ac10
    *tests = 0x600000000
    

P.S.: Updated cycle code from one monstrous line to step by step actions.

5
  • 1
    Sorry, I can't read that line of code, thus can't understand what the intent is. Thus I can't help you figure out a better way of writing it! Please explain what the intent of the code is. Commented Nov 19, 2014 at 20:51
  • I asked not about cout, it was used just for debugging, @cacho Or do you think it adds something different to the source logic? Commented Nov 19, 2014 at 20:53
  • 3
    *tests = (TestCase*)malloc(sizeof(TestCase*)); Right here you already are dereferencing an uninitialized pointer. Commented Nov 19, 2014 at 20:58
  • 2
    Instead of putting everything on two long lines of code, why not break it into smaller steps, storing the intermediate results. Commented Nov 19, 2014 at 21:07
  • @NeilKirk Updated source so it is now step by step cycle; Commented Nov 19, 2014 at 21:36

3 Answers 3

4

Assuming that you want tests to be an array-of-pointers-to-struct-TestCase with 5 pointers to 5 structs, then you need to

  • allocate an array of 5 pointers, and
  • initialize each pointer by allocating memory for the struct

Like this:

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

struct TestCase
{
    int id;
};

int main( void )
{
    int i;
    struct TestCase **tests;

    // allocate memory for an array of 5 pointers
    tests = malloc( 5 * sizeof(struct TestCase *) );
    if ( tests == NULL )
        exit( 1 );

    // allocate memory for 5 structures (and save each pointer in the array)
    for ( i = 0; i < 5; i++ )
    {
        tests[i] = malloc( sizeof(struct TestCase) );
        if ( tests[i] == NULL )
            exit( 1 );
    }

    // initialize the id in each struct
    for ( i = 0; i < 5; i++ )
        tests[i]->id = i;

    // print the id in each struct
    for ( i = 0; i < 5; i++ )
        printf( "%d\n", tests[i]->id );

    // free memory
    for ( i = 0; i < 5; i++ )
        free( tests[i] );
    free( tests );

    return 0;
}

I wasn't able to reproduce the problem described in point 2. Here's the code I tried (which I placed ahead of the code that frees memory)

printf( "%p\n", tests );
for ( i = 0; i < 5; i++ )
{
    intptr_t addr = (intptr_t)tests;
    addr += sizeof(struct TestCase)*i;
    addr += (int)&(((struct TestCase*)NULL)->id);

    printf( "%p\n", (void *)addr );
}

The output from the code is

0xc03950
0xc03950
0xc03954
0xc03958
0xc0395c
0xc03960

The address advances by 4 bytes as expected. Note that I changed the type of addr to intptr_t to guarantee that the pointer can be cast properly, but that doesn't effect the math in the subsequent two lines.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for solution with tests[i]->id. Now I see my problem. Points 1 and 3 are answered by this, but still I want to do something with 2. This line looks so awesome to me, that it looks like code obfuscation by itself ) Updated that line to 3 lines in step by step instructions as people asked in comments.
@ArturKorobeynyk I wasn't able to duplicate the problem where the address jumps by 32 bytes. I've updated the answer with an explanation.
Well, does not matter already. Thanks dude! Thanks to your explanation I was able to deal with point 2. I posted the solution below. You saved my day )
1
  1. In your code tests is triple *, remove the additional * from the malloc line and test[0]->id assignments will work.

  2. If you need a high level access to an offset, assign values as you initially wanted to in question 1. IE - tests[0]->id = 0x3834 , or memcpy for dynamic assignments. There´s no need for all those references and casts.

  3. Because tests was reassinged in the first line of your iterator.

1 Comment

Thanks for answer, but as for 2. that was the point, to make that line work ) Just for fun
0

Thanks to @user3386109 I was able finally to do everything I wanted. Well, instead of writing to address using creepy formula I am now reading from address using the same creepy formula:

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

    using namespace std;

    struct TestCase{
        int ida;
        int idb;
    };

    int main()
    {
        TestCase ** tests; //create pointer to pointer
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        tests = malloc(sizeof(TestCase*)*5);
        if(tests == NULL)
            exit(1);
        for(int i=0; i< 5; i++)
        {
            tests[i] = malloc(sizeof(struct TestCase));
            if(tests[i] == NULL)
                exit(1);
        }
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            tests[i]->ida = i;
            tests[i]->idb = i+6;
            cout << std::hex << &(tests[i]->idb) << ": " << *(long*)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb)) << endl;
        }
        for(int i=0; i<5; i++)
        {
            free(tests[i]);
        }
        cout << "*tests = " << *tests << endl;
        free(tests);
        return 0;
    }

Output:

    $ ./a.exe
    Size of TestCase: 8
    *tests = 0x600048630
    0x600048634: 6
    0x600048654: 7
    0x600048674: 8
    0x600048694: 9
    0x6000486b4: a
    *tests = 0x600048630

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.