Initialize sized, static string lists in C - c

I want to create string lists with a discoverable size and am not sure if I have the right method/syntax. Here is my attempt:
typedef struct {
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Is this the right approach? Note that I do not want to hardcode the size into the structure because I want to use the same type to define many different lists. For example, imagine the following function:
void printList( STRLIST* pList ){
for( int x = 0; x < pList->size; x++ ) printf( "%s\n", pList->list );
}

It can be done with C99 compound-literals and a slight change:
http://coliru.stacked-crooked.com/a/4497d2645ad21b74
typedef struct STRLIST{
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = (char*[]){
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Alternative for C90 (thus without compound-literals and designated initializers): http://coliru.stacked-crooked.com/a/5cc95d25afc18c91
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
};
static STRLIST listMediaType = {
sizeof list / sizeof *list,
// Used sizeof to avoid manually typing the lists length
list,
};
As an aside, an array with a sentinel-NULL is far simpler than a counted array.
Does not even need a new type.
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal",
0
};
void printList(char** pList){
while(*pList) printf( "%s\n", *pList++);
}

You may check this code:
#include <stdio.h>
typedef struct {
unsigned int size;
char* list[];
} STRLIST;
static STRLIST listMediaType = {
7,
{
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
}
};
int main() {
printf("struct size: %d\n", listMediaType.size);
int i;
for (i = 0; i < listMediaType.size; i++)
printf("struct elem[%d] = \"%s\"\n",
i,
listMediaType.list[i]);
return 0;
}
I think there are 2 problems in your approach:
Is TYPEDEF syntactic correct in C? I think you should write it in lowercase.
If you want to initialize a struct, just use the brace and without .attributes
Hope this one will help.
Thanks

Related

How to get the value of enum from a string

code is here!
I tried to get the value of enum value as string from the user input and want to decode the value and print the case according to it, using Switch case but can't decode the exact value.
enum design {E2F = 1, E2, E3, E4, E5}; char *designation[5];
If someone helps I will be happy
Thanks.
An enum maps symbols to numbers. Here are the 3 options we discussed:
If you want to map strings to numbers use a struct:
struct {
const char *design;
int value;
} designs[] = {
{"E2F", 1},
{"E2", 2},
{"E3", 3}
{"E4", 4},
{"E5", 5}
};
If you want the struct defined in terms of the enum. Generate both from the same data (DESIGNS):
#define DESIGNS\
_(E2F, 1)\
_(E2, 2)\
_(E3, 3)\
_(E4, 4)\
_(E5, 5)
#define _(A, B) A = B,
enum {
DESIGNS
};
#undef _
#define _(A, B) { #A, A },
struct {
const char *design;
int value;
} designs[] = {
DESIGNS
};
which the pre-processor would expand to:
enum {
E2F = 1, E2 = 2, E3 = 3, E4 = 4, E5 = 5,
};
struct {
const char *design;
int value;
} designs[] = {
{ "E2F", E2F }, { "E2", E2 }, { "E3", E3 }, { "E4", E4 }, { "E5", E5 },
};
And here is #DavidCRankin's suggestion (if I understood it right) to just store the array to derive the value from the index:
#include <string.h>
int design_to_number(const char *str) {
const char *designs[] = { "E2F", "E2", "E3", "E4", "E5" };
for(int i = 0; i < sizeof(designs) / sizeof(*designs); i++) {
if(!strcmp(designs[i], str)) return i + 1;
}
return -1;
}
C enum values are just named integers. For string conversion, you'll need to roll our own (unlike Java, for example, where enums are more powerful). One way to go about conversion from string to enum is use the library bsearch function:
#include <stdlib.h>
#include <assert.h>
#include <string.h>
enum design {E2F = 1, E2, E3, E4, E5};
struct design_value {
const char *design;
enum design value;
} designs[] = {
{"E2", E2},
{"E2F", E2F},
{"E3", E3},
{"E4", E4},
{"E5", E5},
};
static int design_value_cmp(const void *a, const void *b) {
return strcmp(((struct design_value*) a)->design, ((struct design_value*) b)->design);
}
enum design get_design(char *designation) {
struct design_value key[1] = {{ designation }};
struct design_value *result = (struct design_value*) bsearch(
key,
designs, sizeof designs / sizeof designs[0], sizeof designs[0],
design_value_cmp);
assert(result);
return result->value;
}
// Tiny verifier. Don't use scanf("%s"...) in real code.
#include <stdio.h>
int main(void) {
char buf[100];
scanf("%s", buf);
printf("%d\n", get_design(buf));
return 0;
}
Note bsearch requires that the strings be in alpha order.

How to declare and initialize an array of pointers to array of pointers to char?

I want to declare an array of pointers to array of pointers to char and initialize it. But i couldn't declare and initialize it using the following way:
char *(*array[])[] = {
{ "car", "toy", "game" },
{ "go", "play", "read" }
};
Please write the correct form of my declaration and initialization?
I get warning messages like "warning: brace around scalar initializer"
and also "note: (near initialization for 'array[0]' )"
Before C99, you had to define the inner arrays separately:
#include <stdio.h>
int main() {
const char *array_0[] = { "car", "toy", "game" };
const char *array_1[] = { "go", "play", "read" };
const char **array[] = { array_0, array_1 };
int i, j;
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
printf("%s ", array[i][j]);
}
printf("\n");
}
return 0;
}
With C99, you can now define and initialize the same object directly:
#include <stdio.h>
int main() {
const char **array[] = {
(const char *[]){ "car", "toy", "game" },
(const char *[]){ "go", "play", "read" },
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%s ", array[i][j]);
}
printf("\n");
}
return 0;
}
Of course this is more flexible than a 2D matrix: each inner array can have a different size, as in:
#include <stdio.h>
int main() {
const char **array[] = {
(const char *[]){ "car", "toy", "game", NULL },
(const char *[]){ "go", "play", NULL },
(const char *[]){ "read", NULL },
NULL,
};
for (int i = 0; array[i]; i++) {
for (int j = 0; array[i][j]; j++) {
printf("%s ", array[i][j]);
}
printf("\n");
}
return 0;
}
Output:
car toy game
go play
read
Note that I added the const keyword because string literals should not be modified, so pointers to them should be defined as const char *.
char *(*array[])[] = {
&(char*[]){"car","toy","game" },
&(char*[]){"go","play","read" }
};
compiles without a warning.
It's not nested arrays, it's an array of pointers (&) to arrays of char* (char*[]`) so I don't think you can do without either compound literals or separate array objects to make array pointers out of.
(Don't forget that assigning to char* from string literals is kind of a bad practice as string literals are practically, though not formallychar const[], so usingchar const*instead ofchar *` would be preferable.)

mapping structures in struct C

im trying to index number of struct under one struct.
im tying to pass the data in the first struct to the struct pointer but i get return null.
my code is :
struct complex{
char * rNum; /* real number */
char *iNum; /* imaginary number*/
};
struct complex A = {"0","0"};
struct complex B = {"0","0"};
struct complex C = {"0","0"};
struct complex D = {"0","0"};
struct complex E = {"0","0"};
struct complex F = {"0","0"};
struct mapping{
char *key;
struct complex *P;
} complex_map [] = {
{ "A", &A },
{ "B", &B },
{ "C", &C },
{ "D", &D },
{ "E", &E },
{ "F", &F },
};
char call_complex(const char *name) {
int i;
for (i = 0; i < (sizeof(complex_map) / sizeof(complex_map[0])); i++) {
if (!strcmp(complex_map[i].key, name) && complex_map[i].P->rNum) {
complex_map[i].P->rNum;
return 0;
}
}
printf("Invalid\n");
}
and my call function is :
void read_comp(char *str){
printf(" %s",call_complex(str));
}
when i run this code i get return (null)
why?
thanks for helping
Try This:
#include <stdio.h>
struct complex{
char * rNum; /* real number */
char *iNum; /* imaginary number*/
};
struct complex A = {"1","0"};
struct complex B = {"2","0"};
struct complex C = {"3","0"};
struct complex D = {"4","0"};
struct complex E = {"5","0"};
struct complex F = {"6","0"};
struct mapping{
char *key;
struct complex *P;
} complex_map [] = {
{ "A", &A },
{ "B", &B },
{ "C", &C },
{ "D", &D },
{ "E", &E },
{ "F", &F },
};
char call_complex(const char *name)
{
int i;
for (i = 0; i < (sizeof(complex_map) / sizeof(complex_map[0])); i++)
{
if (!strcmp(complex_map[i].key, name) && complex_map[i].P->rNum)
{
return *(complex_map[i].P->rNum); // Correction
}
}
printf("Invalid\n");
}
int main()
{
printf("Got: %c \n",call_complex("A")); // Just example
return 0;
}
Thanks.

sizeof reporting wrong value

I'm trying to get a "column" elements count from my own structure using sizeof(_test.header.columns)/sizeof(struct _column). Unfortunately I'm always getting it as 0, because the sizeof(_test.header.columns) is always 4. Here is the code:
struct _column{
char title[40];
int length;
};
struct test_struct{
struct{
struct _column* columns;
}header;
struct{
struct _column* columns;
}details;
struct{
struct _column* columns;
}end;
};
struct test_struct _test = {
.header = {
.columns = {
{
"a",
1,
},
{
"ab",
2,
},
},
},
.details = {
.columns = {
{
"b",
2,
},
{
"bc",
3,
},
},
},
.end = {
.columns = {
{
"c",
3,
},
{
"cd",
4,
},
},
},
};
void testme(){
char buff[20];
itoa(sizeof(_test.header.columns)/sizeof(struct _column),buff,sizeof(buff));
MessageBoxA(NULL,buff,NULL,NULL);
}
please help me to resolve the problem, thanks. Any help would be appreciated.
You might try to do an approach like the following in which you do the same kind of initialization however you include as part of it the column count itself.
struct _column{
char title[40];
int length;
};
struct test_struct{
struct{
struct _column* columns;
int nColumns;
}header;
struct{
struct _column* columns;
int nColumns;
}details;
struct{
struct _column* columns;
int nColumns;
}end;
};
struct _column headerColumns [] = {
{
"a",
1
},
{
"ab",
2
}
};
struct _column detailColumns[] = {
{
"b",
2
},
{
"bc",
3
},
};
struct _column endColumns [] = {
{
"c",
3
},
{
"cd",
4
}
};
struct test_struct _test = {
{ headerColumns, sizeof(headerColumns)/sizeof(headerColumns[0])},
{ detailColumns, sizeof(detailColumns)/sizeof(detailColumns[0])},
{ endColumns, sizeof(endColumns)/sizeof(endColumns[0])}
};
The reason it fails is that you're checking the sizeof on a pointer, which returns the size of the pointer, NOT of the actual Array the memory address points to.
If you know the maximum length of the array, you can declare it as such:
_column[ integerSize ]
But then if you knew the size, you wouldn't be querying it using sizeof, I'd think ;-) You could extend the struct by adding another property of an int type that describes the size of the columns array ?

changing size of array

I have the following code:
typedef struct my_data {
char* name;
}my_data;
my_data data[]={
{ .name = "Peter" },
{ .name = "James" },
{ .name = "John" },
{ .name = "Mike" }
};
void loaddata()
{
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
memset(data, 0, sizeof(data));
int i = 0;
while(!feof(in))
{
fscanf(in,"%s", &data[i].name);
i++;
};
fclose(in);
}
}
to read contents and process them I use this:
for (i=0; i<sizeof(data)/sizeof(data[0]); i++)
but if the number of lines in file is less than the number of defined array I get a lot of empty records so I modified it into:
for (i=0; (i<sizeof(data)/sizeof(data[0])) && strlen(data[i].name)>0; i++)
which is working fine but I'm sure I will get errors if the number of lines in file will be larger than the defined array size.
Any idea how to make this code safe? To change array dynamically?
EDIT:
this way is working with size 300
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct my_data {
char name[100];
}my_data;
struct my_data data[300];
my_data data_arr[]={
{ .name = "Peter" },
{ .name = "James" },
{ .name = "John" },
{ .name = "Mike" }
};
void process_data()
{
char name[100];
int i;
for (i=0; (i<sizeof(data)/sizeof(data[0])) && strlen(data[i].name)>0; i++) {
sprintf(name, "%s", data[i].name);
printf("%s\n", name);
}
}
void load_data()
{
int i = 0;
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
while(!feof(in))
{
fscanf(in,"%s", &data[i].name);
i++;
};
fclose(in);
}
else
{
for (i=0; (i<sizeof(data_arr)/sizeof(data_arr[0])) && strlen(data_arr[i].name)>0; i++) {
sprintf(data[i].name, "%s", data_arr[i].name);
}
}
return;
}
int main()
{
load_data();
process_data();
return 0;
}
Arrays do not grow dynamically in C. So you have a few approaches:
get a pointer to a block of memory (using malloc) and use realloc whenever you need more space for an array - and index into your pointer
create a linked list using malloc for every new item you want to add to your list
Don't forget when using malloc to call free on every single block that you called malloc for.

Resources