1

I wanted to access the array elements using the struct attributes. I am able to print 1st and the 2nd element using the struct pointer (nameptr) while the remaining 3 elements has to be accessed using the (uint8_t ptr) which itself is a attribute of the 'struct name'.

#include <iostream>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;

}*nameptr;

int main()
{
    
    uint8_t arr[]= {1,2,3,4,5};
    nameptr = (name *)arr;
    nameptr->ptr = arr+2;
    printf("%d ", nameptr->b0);           //prints 1
    printf("%d ", nameptr->b1);           //prints 2
    for (int i=2; i<5; i++){
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
    }

    return 0;
}

When compiled I get the below error, Please help me getting this error solved.

*** stack smashing detected ***: ./a.out terminated

1 2 5 0 56 Aborted (core dumped)

Vasuda R
  • 11
  • 4
  • 2
    There are not even layout compatible... – Jarod42 Feb 26 '21 at 11:52
  • The correct syntax would be `nameptr->ptr[1]` or `*(nameptr->ptr+1)`, but your struct cannot alias an array. – mch Feb 26 '21 at 11:53
  • Try `uint8_t ptr[];` since you're trying to use it as an array, not a pointer. – paddy Feb 26 '21 at 11:54
  • 1
    Is `nameptr->*(ptr)` supposed to be `*(nameptr->ptr)`? It's UB anyway (twice actually). – Lukas-T Feb 26 '21 at 11:54
  • That's obviously C++. I removed the C tag. – Thomas Sablik Feb 26 '21 at 11:55
  • Is this really C++? – Ted Lyngmo Feb 26 '21 at 11:56
  • 2
    May I recommend [a good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)? None of this can work, and I have no idea what are you even trying to do there. – Yksisarvinen Feb 26 '21 at 11:56
  • 1
    C or C++? They are slightly different when it comes to wild type casts like `(name *)arr`. It's undefined behavior in both languages, but C has some work-arounds, C++ doesn't. – Lundin Feb 26 '21 at 11:56
  • @TedLyngmo There are no namespaces and no header `iostream` in C. – Thomas Sablik Feb 26 '21 at 11:56
  • `(name *)` wouldn't work in C either, actually. In C++ it's a type, in C it's a struct tag so `struct name*` is needed. – Lundin Feb 26 '21 at 11:57
  • @ThomasSablik True ... I'm still feeling reluctant calling this C++ :-) – Ted Lyngmo Feb 26 '21 at 11:59
  • 1
    @TedLyngmo At least it's not C :-) – Thomas Sablik Feb 26 '21 at 12:00
  • 1
    @VasudaR Why include `iostream` and then use `std::printf`? You need to include `cstdio` for that. – Ted Lyngmo Feb 26 '21 at 12:00
  • The question has been edited. Now I get an error like this *** stack smashing detected ***: ./a.out terminated 5 0 208 Aborted (core dumped) How can this be resolved? – Vasuda R Feb 26 '21 at 12:07
  • 3
    I recommend that you follow @Yksisarvinen's advice and pick up a book on C++. Your code is confusing and does illegal things. What is the purpose of the code? Perhaps we can help you to achieve your goal without `reinterpret_cast`s. – Ted Lyngmo Feb 26 '21 at 12:09
  • 1
    After changing your code it has completely different errors. You won't get a good understaning of how pointers work by guessing. For example `nameptr->ptr = arr+2;` - where does `nameptr->ptr` point now? The loop then starts at 2, so where will `nameptr->ptr+2` then point? – Lukas-T Feb 26 '21 at 12:12

3 Answers3

1

This answer is based on the modified code as in revision 6 of the question.

If you have a structure of type name, not only a pointer, you can assign the array address to the pointer element ptr like this.

#include <cstdio>
#include <cstdint>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;

}*nameptr;

int main()
{

    uint8_t arr[]= {1,2,3,4,5};
    name name_struct; // actual memory where you can access the structure fields
    nameptr = &name_struct; // pointer now points to a real structure of the correct type
    nameptr->ptr = arr; // assign array to pointer inside structure

    /* For this loop you must know the size of the array the pointer is pointing to.
     * Your code cannot automatically derive this information from the
     * pointer element `ptr` or from the structure like you could with
     * sizeof(arr)/sizeof(arr[0]). */
    for (int i=2; i<5; i++){
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
        // printf("%d ",nameptr->ptr[i]);  // same, but easier to understand
    }

    return 0;
}

The code in revision 7 of the question is wrong in several ways:

struct name{
    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;
}*nameptr;

/* Depending on your platform, the structure might be something like this */
struct name_with_padding {
    uint8_t b0; // 1st byte
    uint8_t b1; // 2nd byte
    // uint8_t padding[2]; // 3rd and 4th byte 
    uint8_t* ptr; // 5th to 8th byte
}*nameptr;

uint8_t arr[]= {1,2,3,4,5};

/* This cast is the main error. It will interpret the memory of the array
 * as a structure as shown above which is undefined behavior (and 
 * implementation dependent).
 * It might result in:
 * b0 = 1
 * b1 = 2
 * padding = {3, 4}
 * ptr = value 5 + some (3) bytes after it
 * But it may as well result in other (undefined) behavior.
 */
nameptr = (name *)arr;

/* This may (depending on your implementation) overwrite
 * overwrite the value 5 and the following (3) bytes
 * with the address arr+2
 * so it will change the value of arr[4] and the memory after it
 * This may (or may not) result in a segmentation fauult or stack corruption.
 */ 
nameptr->ptr = arr+2;
Bodo
  • 9,287
  • 1
  • 13
  • 29
  • This solves my error.. Also, I will edit the indexing part of the array in the question – Vasuda R Feb 26 '21 at 14:11
  • @VasudaR Maybe I got you wrong, but you don't need to edit the code in your question to match the answer. Of course you can edit the code you will actually use. – Bodo Feb 26 '21 at 14:39
0

This answer is based on the original code in the first revision of the question and on my interpretation about the intention behind the wrong code.

See also my other answer based on the code in revision 6 of the question.

The structure element uint8_t* ptr; is a pointer, not an array. That's why, when doing nameptr = (name *)arr; and dereferencing nameptr->ptr, you interpret the data in memory as an address and try to access the memory at this address. The address is probably constructed from the bytes 3, 4, 5 and whatever follows it in memory. (implementation dependent)

This modified version of the original code might do what you want, but casting the array pointer arr to a structure pointer and accessing the structure elements is undefined behavior and highly depends on your implementation. (There might be padding between the array elements.)

#include <cstdio>
#include <cstdint>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t array[3];

} name1, *nameptr;

int main()
{
    
    uint8_t arr[]= {1,2,3,4,5};
    nameptr = (name *)arr;
    printf("%d\n",(int)nameptr->b0);
    printf("%d\n",(int)nameptr->b1);
    printf("%d\n",(int)nameptr->array[0]); //should print 3
    printf("%d\n",(int)nameptr->array[1]); //should print 4
    printf("%d\n",(int)nameptr->array[2]);

    return 0;
}

On the specific platform where I tested the program, the output is

1
2
3
4
5

see https://onlinegdb.com/HyY8BDUz_

But in fact it is undefined behavior and may produce different results depending on your implementation.

Bodo
  • 9,287
  • 1
  • 13
  • 29
  • Can you please make 'uint8_t array[3]' in struct name to 'uint8_t* ptr'? Since I want to access last three elements using the pointer – Vasuda R Feb 26 '21 at 12:21
  • 2
    "_The output is_" undefined. Every time the program is executed. @VasudaR What are you really trying to do? Instead of us helping you to paint yourself into a corner - please describe the purpose and someone can probably help you to get there without making programs with undefined behavior. – Ted Lyngmo Feb 26 '21 at 12:22
  • @TedLyngmo I wanted to access and print the 3rd,4th and 5th element of the array arr[] using the pointer "ptr" in the "struct name". – Vasuda R Feb 26 '21 at 12:37
  • 1
    @VasudaR Why do you want to use a pointer to an unrelated type to do so? – Ted Lyngmo Feb 26 '21 at 12:38
  • 1
    @VasudaR Please explain in your question (instead of in comments) what you want to achieve and what's the intended use case. – Bodo Feb 26 '21 at 12:40
  • 1
    @VasudaR Ok. I hope that the lesson is that even if a program with undefined behavior seems to work the way you hoped Today - you can't be sure that it will do the same Tomorrow. – Ted Lyngmo Feb 26 '21 at 12:47
0

Apart the Undefined Behaviour that is invoked by casting an array to a struct, there is a size problem.

This is a slight variation of your code, still invoking UB, hat at least with no runtime error on gcc:

...

int main()
{

    uint8_t arr[sizeof(name)]= {1,2,3,4,5};
    nameptr = (name *)arr;
    nameptr->ptr = arr+2;
    for (int i=0; i<3; i++){  // SB: starting at 2 so only 0 to 3...
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
    }

    return 0;
}

And when I execute this code under a debugger, I can see that arr has now size 8 (on my 32 bits environment). Because the actual layer of name is:

* b0
* b1
* padding bytes size 2
* ptr (size 4)

So in your original code, when you executed nameptr->ptr = arr+2; you were writing well past of the declared array, which is a nice recipe for SIGSEGV or other weird errors.


But anyway my code does not print 3, 4, 5. Even if it invokes undefined behaviour, my implementation does write the first byte of ptr at the place where was the 5 (see the above layer to understand why...). So I get 3, 4 and a random byte!

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252