iterate through null terminated array - c

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;
}

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

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;
}

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.

Related

Initialize a flexible array of arrays in a struct

The title corresponds to my last attempt, I try to store color values ​​corresponding to walls, a bit like this:
#include <stdint.h>
typedef uint8_t RGB[3];
typedef RGB ColorArray[];
typedef struct {
int wall_num;
ColorArray wall_colors;
} Map;
int main(void)
{
int wall_num = 3;
ColorArray wall_colors = {
*(RGB){ 255, 0, 0 },
*(RGB){ 0, 255, 0 },
*(RGB){ 0, 0, 255 }
};
Map my_map = {wall_num, wall_colors}; // error: non-static initialization of a flexible array member
return 0;
}
But I get this:
error: non-static initialization of a flexible array member
I tried other ways with pointers but I quickly realized that it was pointing to anything and so I got any colors until a segfault...
Is there a way to do it like this ? Or is it just the wrong way to go and I have to start all over again ?
UPDATE - (SELF ANSWER):
So I decided to call malloc() because no alternative was satisfactory for my case, I share what I did if it can help someone:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef uint8_t RGB[3];
typedef RGB RGB_Array[];
typedef struct {
int wall_num;
RGB_Array wall_colors;
} Map;
void print_map (Map *m) {
printf("wall_num: %d\n", m->wall_num);
for (int i = 0; i < m->wall_num; ++i) {
printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
m->wall_colors[i][0],
m->wall_colors[i][1],
m->wall_colors[i][2]);
}
}
int main(void)
{
int wall_num = 3;
RGB_Array color_arr = {
{255,0,0},
{0,255,0},
{0,0,255}
};
Map* map = malloc(sizeof(Map) + sizeof(color_arr));
map->wall_num = wall_num;
memcpy(map->wall_colors, color_arr, sizeof(color_arr));
print_map(map);
free(map); // free is for example
return 0;
}
Otherwise, jxh's answer is still interesting and perfectly does what was asked for, even if it doesn't suit me personally, I validate it anyway.
You cannot use an array name to initialize an array variable anyway.
There is no memory associated with the flexible array member. It is a convenience to allow you to have a name for the end of the struct to refer to the array that you intend to allocate behind the struct.
Typically, you would use malloc() and add the size of the array to the size of the struct to get a single object to represent your structure with the flexible array.
However, you can do it off the "stack" by defining a new structure where the flexible array member is replaced with an array of the appropriate size, and then casting a pointer to this structure to your desired type.
Alternatively, you could use a union and avoid the casting.
Both techniques are illustrated below. First some helpers:
...
#define MAP_TEMPLATE(N) struct { \
int wall_num; \
RGB wall_colors[N]; \
}
...
void print_map (Map *m) {
printf("wall_num: %d\n", m->wall_num);
for (int i = 0; i < m->wall_num; ++i) {
printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
m->wall_colors[i][0],
m->wall_colors[i][1],
m->wall_colors[i][2]);
}
}
Then using a new structure:
MAP_TEMPLATE(3) my_map1 = {
wall_num,
{ { 155, 0, 0 },
{ 0, 155, 0 },
{ 0, 0, 155 },
},
};
print_map((Map *)&my_map1);
And using a union:
union {
MAP_TEMPLATE(3) _;
MAP_TEMPLATE();
} my_map2 = {
{ wall_num,
{ { 255, 0, 0 },
{ 0, 255, 0 },
{ 0, 0, 255 },
},
},
};
print_map((Map *)&my_map2);

What is the problem here in struct definition and compiler error?

When I type the following code:
struct student {
int* grades;
int num_grades;
};
int main()
{
struct student s1 = { { 100, **50**, 74}, 3 }, s2 = { {100, **90**, 80, 90, 90}, 5 }, s3 = { {85, **90**}, 2 };
struct student arr[3] = { s1, s2, s3 };
}
I get two errors error:
C2078 too many initializers
E0146 too many initializer values
I've marked the numbers with two bold asterisks to tell you where the Visual Studio puts red underline.
Does anyone know why the compiler tells me that error?
You cannot initialize a pointer (grades variable) by brace-enclosed initializer list. You need to make use of a compound literal.
Something like
struct student s1 = { (int []){ 100, 50 , 74}, 3 };
should do the job.

Array of structure pointer in C

I am running following code.
#include <stdio.h>
struct point
{
int formatbyte1;
int formatbyte2;
int formatbyte3;
};
const struct point SW_VERSN_POINT =
{
1,2,3
};
const struct point SWMVERSN_POINT =
{
4,5,6
};
const struct point *object_directory[] =
{
&SW_VERSN_POINT,
&SWMVERSN_POINT,
0
};
int main()
{
printf("%ld\n", sizeof(SW_VERSN_POINT.formatbyte1));
printf("%ld 0X%X, 0x%X\n", sizeof(struct point), &SWMVERSN_POINT.formatbyte1, &SW_VERSN_POINT.formatbyte1);
printf("%ld 0X%X, 0x%X\n", sizeof(object_directory), object_directory[0], object_directory[1]);
return 0;
}
The output of above program is
4
12 0XE2BF0788, 0xE2BF0778
24 0XE2BF0778, 0xE2BF0788
But when I modified the object_directory, removed 0 from it
const struct point *object_directory[] =
{
&SW_VERSN_POINT,
&SWMVERSN_POINT
};
Now output of above program is
4
12 0XF967D788, 0xF967D778
16 0XF967D778, 0xF967D788
Why is the size of object_directory is changes from 24 to 16. (How does 16 come from)
Thanks in advance.
This code is running on Linux.

Pointer to array of pointers points to unexpected address

The question is related to my former question here:
Arduino compile error while using reference to a struct in another struct
I ported the sample code back to the pc and compiled it to get a clue, what's going wrong.
Here's the sample:
#include <stdio.h>
unsigned int steps=64;
unsigned int mode=0;
unsigned int speed=1;
typedef struct{
unsigned int option_value;
char option_name[17];
} SELECTION;
typedef struct{
char item_name[17];
unsigned int* variable;
SELECTION** options;
} MENU_ITEM;
SELECTION mode_forward = { 0, "Forward" };
SELECTION mode_backward = { 1, "Backward" };
SELECTION* options_mode[] = { &mode_forward, &mode_backward };
SELECTION speed_slow = { 0, "Slow" };
SELECTION speed_normal = { 1, "Normal" };
SELECTION speed_fast = { 2, "Fast" };
SELECTION* options_speed[] = { &speed_slow, &speed_normal, &speed_fast };
MENU_ITEM menu_steps = { "Steps", &steps, NULL };
MENU_ITEM menu_mode = { "Mode", &mode, options_mode };
MENU_ITEM menu_speed = { "Speed", &speed, options_speed };
MENU_ITEM menu_exit = { "Exit", NULL, NULL };
const unsigned char menu_items = 4;
MENU_ITEM* menu_list[menu_items] = { &menu_steps, &menu_mode, &menu_speed, &menu_exit };
//-----------------------------------------------------------
int main(){
int options;
options=(int)(sizeof(options_speed)/sizeof(options_speed[0]));
printf("Speed options: %i\n\n",options);
printf("Address of speed_slow: %p\n",&speed_slow);
printf("Address of speed_normal: %p\n",&speed_normal);
printf("Address of speed_fast: %p\n",&speed_fast);
printf("Address of array: %p\n\n",&options_speed);
MENU_ITEM item;
item=*menu_list[2];
printf("Menu Item: %s - Item Value: %i\n",item.item_name,*item.variable);
printf("Address of name: %p\n",&item.item_name);
printf("Address of variable-pointer: %p\n",&item.variable);
printf("Address of options-pointer: %p\n",&item.options);
printf("Value of options-pointer: %p\n",*item.options);
return 0;
}
When i start the program i get the following output:
Speed options: 3
Address of speed_slow: 0x6010c0
Address of speed_normal: 0x6010e0
Address of speed_fast: 0x601100
Address of array: 0x601120
Menu Item: Speed - Item Value: 1
Address of name: 0x7fff18a5dc90
Address of variable-pointer: 0x7fff18a5dca8
Address of options-pointer: 0x7fff18a5dcb0
Value of options-pointer: 0x6010c0
That's what i expect....except the last line. Shouldn't the address that it points to be 0x601120 - the address of options_speed array?
Why does it point to the first member of the array instead?
What do i have to change to let it point to 0x601120?
You are evaluating *item.options, not item.options. This seems is not what you wanted to print (i.e. the "options pointer") as there is an extra dereferencing operation.

How do you convert values to enumeration constants in c?

Earlier I was fixing a lexer for my parser; now I have to create a validater for it. My idea was to convert the enumeration constants to strings by using the following preprocessor macro: #define MACRO_STRINGIFY(x) #x.
Then I made a function to compare various token values lactually, I made three, but they are all the same with a few minor changes):
unsigned int compare_keyword( enum script_keywords keyword, char *token ) {
char *temporary = MACRO_STRINGIFY( keyword );
unsigned int i = 0;
for (; i < (strlen( "KEYWORD_" ) + 1); i++) {
++temporary;
}
// 0 on match, 1 on no match
return strcmp( temporary, token ) ? 1 : 0;
}
Now, this function works absolutely fine... when keyword is the enumeration constant:
void test() {
printf( "\nIF is " );
// Finish the sentence based on the return value
compare_keyword( KEYWORD_IF, "IF" ) ? printf( "not a keyword.\n" ) : printf( "a keyword.\n" );
}
test(); //--> Outputs 'IF is a keyword' like expected.
On the other hand, the function does not work as intended if I pass a value like 1 (the value which the symbolic enumeration constant KEYWORD_IF resolves to.):
// Same as last time with one edit:
void test() {
/* See above code with following change on line 4 */
compare_keyword( 1, "IF" ) /* etc... */
/* Rest of code from previous test */
}
test(); //--> Outputs 'IF is not a keyword' even if KEYWORD_IF resolves to the value 1.
The point I'm getting across here is that the preproccessor is very literal, and I would much prefer using a for loop to loop through the constants efficiently without bloating the code size (which is what would happen if I end up using enumeration constants). Therefore, the question is how can I convert plain integer values to their symbolic names without using switch…case… or if…else…?
Edit: Enumeration Details:
enum script_keywords {
KEYWORD_IF = 1,
KEYWORD_THEN = 2,
KEYWORD_ELSEIF = 3,
KEYWORD_ELSE = 4,
KEYWORD_ENDIF = 5,
KEYWORD_FOR = 6,
KEYWORD_TO = 7,
KEYWORD_STEP = 8,
KEYWORD_EXITFOR = 9,
KEYWORD_NEXT = 10,
KEYWORD_LOOP = 11,
KEYWORD_WHILE = 12,
KEYWORD_EXITLOOP = 13,
KEYWORD_ENDLOOP = 14,
KEYWORD_DO = 15,
KEYWORD_EXITDO = 16,
KEYWORD_UNTIL = 17,
KEYWORD_ON = 18,
KEYWORD_GOTO = 19,
KEYWORD_CALL = 20,
KEYWORD_LET = 21,
KEYWORD_DIM = 22,
KEYWORD_AS = 23
};
The Macro "MACRO_STRINGIFY" is evaluated at compile time by the preprocessor. It will return the actual name of the argument, so
MACRO_STRINGIFY(keyword) -> "keyword"
MACRO_STRINGIFY(KEYWORD_IF) -> "KEYWORD_IF"
MACRO_STRINGIFY(1) -> "1"
Apparently this will not lead to any solution.
Instead one could use a compile-time generated key-value mapping to implement such functionality:
struct map
{
int key;
const char* value;
};
struct map mappings[] =
{
{ KEYWORD_IF, "IF" },
{ KEYWORD_ELSE, "ELSE" }
};
and then simply iterate those mapping entries at runtime to find out what you need:
static int is_keyword(const char* str)
{
int i;
const int count = sizeof(mappings) / sizeof(mappings[0]);
for(i = 0; i < count; i++)
{
struct map* m = &mappings[i];
if(strcmp(str, m->value) == 0)
{
return 1;
}
}
return 0;
}
void test()
{
const char* str = "IF";
const char* what;
if(is_keyword(str))
{
what = "a keyword";
}
else
{
what = "not a keyword";
}
printf("%s is %s.\n", str, what);
}
This is about as minimal as it may get. The executable binary does not normally include names of enumeration values as known from e.g. Java.
To extend this even further, you could do some preprocessor voodoo to generate the mapping array (semi-) automatically. But as I am not a big friend of preprocessor voodoo I will skip that ;)

Resources