0

I want to iterate through null terminated structure array. While loop works fine, but when I try to access any structure fields I get "segfault" in response. What am I doing wrong?

PS I know that it is possible to determine array size and use simple "for" construction. I just want to figure out the source of the problem.

PSS Ok, if array initialization is wrong - how to do it correctly?

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

typedef struct demo
{
    int a;
    int b;
    int c;
} demo;

demo * fieldDefinitions[] =
{
  { 1 , 1,  1 },
  { 2 , 2,  2 },
  { 3 , 3,  3 },
  NULL
};

int main()
{
    demo ** ptr = fieldDefinitions;
    printf( "Array: %d \n", &fieldDefinitions );

    while ( *ptr != NULL )
    {
        printf( "ptr: %d \n", ptr );
        printf( "ptr: %d \n", (**ptr).a ); // <--- problem here
        ptr++;
    }

    return 0;
} 
11
  • 2
    you want to use %p to printf pointer Commented Jul 3, 2014 at 11:56
  • 3
    Turn on your warnings. Commented Jul 3, 2014 at 11:58
  • 3
    Then you can do (not that nice, but possible) it using compound literals: demo *fieldDefinitions[] = { &(demo){ 1, 1, 1 }, ..., 0 };. Commented Jul 3, 2014 at 12:12
  • 1
    @incogn1to Don't mix "declare" and "define". In C, knowing the difference will save your life. Commented Jul 3, 2014 at 12:20
  • 2
    It's a little odd to have the answer in the question, followed by answers not addressing the question; I made it a comment, because I thought it's not really a good solution. But rereading your question, this seems to be the best solution fulfilling your requirements. Delete the last part from the question, I'll make it an answer… Commented Jul 3, 2014 at 12:27

3 Answers 3

6

As the others already've pointed out: Listen to your compiler, a standard conforming implementation must complain about:

demo * fieldDefinitions[] =
{
    { 1 , 1,  1 }, // <-- note that this is not a pointer to a demo.
    { 2 , 2,  2 },
    { 3 , 3,  3 },
    NULL
};

Also, use p as the printf format specifier for pointers, not d (which is for integer types).

You need pointers to demo objects, so these objects need to be created somehow, so that we can take their addresses. C99 added a feature called compound literals (looking somewhat similar to a cast, however, they are something different) creating unnamed objects:

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

typedef struct demo
{
    int a;
    int b;
    int c;
} demo;

demo * fieldDefinitions[] =
{
    &(demo){ 1 , 1,  1 },
    &(demo){ 2 , 2,  2 },
    &(demo){ 3 , 3,  3 },
    NULL
};

int main()
{
    demo ** ptr = fieldDefinitions;
    printf( "Array: %p \n", (void *)&fieldDefinitions );

    for ( ; *ptr != NULL; ptr++ )
    {
        printf( "ptr: %p\n", (void *)ptr); // I'm not sure, what you really wanted ...
        printf( "*ptr: %p\n", (void *)*ptr ); // ... but I think you meant this
        printf( "ptr: %d\n", (*ptr)->a ); // or (**ptr).a, whatever you prefer
    }

    return 0;
}

The lifetime of an object created via a compound literal is that of the enclosing block or static if used in an initializer for an identifier with static storage duration (as in this example).

HTH

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

1 Comment

+1. Great catch! A compound literal with static storage can be coerced to a pointer. Although, if one's going to use an array like this, that would make it possible to use a for-loop as well, e.g: for (size_t i=0; i < sizeof(fieldDefinitions) / sizeof(*fieldDefinitions) - 1; i++) { ... }.
2
demo * fieldDefinitions[ 4 ] =
{
  { 1 , 1,  1 },
  { 2 , 2,  2 },
  { 3 , 3,  3 },
  NULL
};

You can't do that, as you can not do:

int *arr[] = {1, 2, 3, NULL};

Turning your warnings on you get:

initialization makes pointer from integer without a cast

If you want to use pointer arithmetic you can do somenting like:

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

typedef struct demo
{
    int a;
    int b;
    int c;
} demo;

demo fieldDefinitions[] = {
    { 1 , 1,  1 },
    { 2 , 2,  2 },
    { 3 , 3,  3 },
};

int main(void)
{
    demo *ptr = fieldDefinitions;
    demo *end = &fieldDefinitions[sizeof(fieldDefinitions) / sizeof(fieldDefinitions[0]) - 1];

    do {
        printf( "ptr: %p \n", (void *)ptr);
        printf( "ptr: %d \n", ptr->a);
    } while (ptr++ < end);

    return 0;
} 

1 Comment

as I sad - I'm aware, that I can determine array size and use it in for loop. The question was - how to implement iteration through NULL terminated array. FUI: as mafso kindly pointed out, this does work. demo * fieldDefinitions[] = { &(demo) { 1 , 1, 1 }, &(demo) { 2 , 2, 2 }, &(demo) { 3 , 3, 3 }, NULL };
0
demo * fieldDefinitions[] =
{
  { 1 , 1,  1 },
  { 2 , 2,  2 },
  { 3 , 3,  3 },
  NULL
};

you are claiming that fieldDefinitions will be an array of demo object pointers, but instead you are giving objects themselves.This is the way you initialize an array of structures (except NULL at the end). If your array is static then i suggest creating array of demo with known size such as

unsigned const int fieldDefinitions_size = 3;
demo fieldDefinitions_arr[fieldDefinitions_size] = {
    {1,1,1},
    {2,2,2},
    {3,3,3}
};

And iterate by using fieldDefinitions_size.

Or if you insist on having demo pointer array then you can individually allocate memory for each demo object and assign addresses to fieldDefinitions array. This thread will be useful.

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.