2

Ok, I've got this code :

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

#define ARR_SIZE 5

struct mys
{
    double first;
    unsigned long second;
    char str[10];
};

int main(int argc, char** argv)
{
    size_t i = 0;
    struct mys thes[ARR_SIZE] = 
        {
            {1.1, 1, "First"},
            {2.2, 2, "Second"},
            {3.3, 3, "Third"},
            {4.4, 4, "Fourth"},
            {5.5, 5, "Fifth"}
        };//load array of structures with values

    for (; i < ARR_SIZE; ++i)
        fprintf(stdout, "second->%lu\n", thes[i].second);//loop through array thes and print element second

    return (EXIT_SUCCESS);
}

Now, I want to get the address of the element called second of the zeroth element thes and then use that to loop through the array thes and print each second element.

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

#define ARR_SIZE 5

struct mys
{
    double first;
    unsigned long second;
    char str[10];
};

int main(int argc, char** argv)
{
    size_t i = 0;
    unsigned long * ptr = NULL;//pointer to unsigned long
    struct mys thes[ARR_SIZE] = 
        {
            {1.1, 1, "First"},
            {2.2, 2, "Second"},
            {3.3, 3, "Third"},
            {4.4, 4, "Fourth"},
            {5.5, 5, "Fifth"}
        };

    //first loop
    for (; i < ARR_SIZE; ++i)
        fprintf(stdout, "second->%lu\n", thes[i].second);

    ptr = &thes[0].second;//get the address of the second element of the zero'th array structure and store it in ptr

    // Now I want to use the above pointer ptr to loop through the array thes and display the second element like I did above, but I can't manage to do that.
    //The output of this loop should be the same as the first loop 

    return (EXIT_SUCCESS);
}

So, I've implemented the pointer but I'm having problem writing the code for the second loop. Any help is appreciated.

1
  • @itwasntpete my code is C :) Commented Dec 18, 2013 at 10:00

6 Answers 6

4
for (; i < ARR_SIZE; ++i)
    fprintf(stdout, "second->%lu\n", *( unsigned long * )(( char * )ptr + i * sizeof( struct mys ) ));
Sign up to request clarification or add additional context in comments.

3 Comments

@StoryTelle instead of unsigned long *ptr you could use struct mys *ptr = thes; and in the print statement use ptr->second and then simply increase ptr: ++ptr. It would be simpler.
@VladfromMoscow, it would also be the suggested method. This hack is bound to be read by some overly zealous programmer that will use it somewhere and break the fabric of time and space.
@itwasntpete, Vlad, that was my idea but you'd posted it first, so take 10 from me :)
3

you can't (or more important shouldn't) do that. what you should do is safe the pointer to the first element of the array, so you can iterate it.

struct mys* ptr;

ptr = &thes[0];

for(int i=0; i<10; i++, ptr++)
  fprintf(stdout, "second->%lu\n", ptr->second);

but you have to be careful since there is no end-element, and iteratig [0-10) is only right in case of starting with ptr = &thes[0];.

Comments

2

Your requirements don't make a lot of sense: all you have is a pointer to an unsigned long, there's no information left that identifies the number in question to be part of some particular array of structures.

You can do this, using pointer tricks, but it's certainly not straight-forward or something I'd recommend in general programming.

Why do you need to do this?

I would do it by computing a pointer back up to the structure, to make the iteration cleaner:

const struct mys *mysp = (struct mys *) ((char *) ptr -
                                         offsetof(struct mys, second));

This uses offsetof to "back up" from the pointer to the structure member to the structure itself.

1 Comment

I just like to learn how it's done, I don't have in plan to use this in general programming.
2

You can of course do it. Not nice, not useful, but can be done by manipulating your pointer.

To understand, look at the layout of your array of structures in memory, let's say your array start at address 0x0000 :

0x0000 : array[0].first  - first part of mys.first
0x0004 : array[0].first  - second part of mys.first
0x0008 : array[0].second
0x000c : array[0].str[0-3] - first four elements of your string
0x0010 : array[0].str[4-7] - next four elements
0x0014 : array[0].str[8-9] - last two elements and padding
0x0018 : array[1].first  - second element !

...

So you can see that between the same field of two consecutive elements of the array you have the size of the structure.

To iterate over the same field of several consecutive structures in memory you then just need to declare a pointer pointing to the element of the first structure and increase it by the size of your structure to access the same field of next element of the array.

In your case, it would then look like :

int i;
struct mys my_array[SIZE];
char* my_iterator = &my_array[0].second;
for(i=0; i<SIZE; i++) {
    fprintf(stdout, "second->%lu\n", *(unsigned long*)my_iterator);
    my_iterator += sizeof(mys);
}

But this really doesn't look good, you can improve it a bit, but still it's not good practice to play with pointers when it's not needed.

int i;
struct mys my_array[SIZE];
strut mys* my_iterator = &my_array[0].second;
for(i=0; i<SIZE; i++, my_iterator++) {
    fprintf(stdout, "second->%lu\n", *(unsigned long*)my_iterator);
}

Comments

1

This is a little explanation of Vlad's solution. This is written on c++ (variables declared in the for loop):

We've casted our ptr to unsigned char* (byte ptr) and then incremented it by the number of bytes the mys occupies to set it to the next element's second. Then we've casted it back to the ulong, and dereferences the pointer to get its value.

ptr = &thes[0].second; //get the address of the second element of the zero'th array structure and store it in ptr
for (i = 0; i < ARR_SIZE; ++i)
{
    unsigned char* pointer_as_byte = (unsigned char*)ptr; // get ptr as byte ptr to increment it
    unsigned char* pointer_offset = pointer_as_byte += (i * sizeof(struct mys)); // next structure's [second] field
    unsigned long* final_pointer = (unsigned long*)pointer_offset; // cast byte ptr back to ulong ptr

    fprintf(stdout, "second->%lu\n", *final_pointer);
}

Or the other way, maybe it's simpler to understand:

ptr = &thes[0].second;//get the address of the second element of the zero'th array structure and store it in ptr
for (i = 0; i < ARR_SIZE; ++i)
{
    mys* pointer_as_mys = (mys*)ptr; // get ptr as mys pointer
    pointer_as_mys += i; // increment is to i'th mys.second
    ptr = (unsigned long*)pointer_as_mys; // cast it back to save the offset to ptr

    fprintf(stdout, "second->%lu\n", *ptr);
}

Comments

0

You can't do that. At least not simply. Your array is of structures. And they sit consecutively in memory. Incrementing your pointer ptr without any casts, will move it to the next long address in the block of memory, which is not in the next structure, but right next to it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.