Array of pointers to structs

F

Frank M.

I'm trying to declare an array of pointers to structures so that I can make
the last element a NULL pointer. I figure that it would more easily allow
my library routines to know when to stop processing the array.

typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;


If I try to declare it like the following:

SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL
};

I get the error "Cannot convert 'int' to 'screen_disp *' " I've tried
various ways of declaring 'display_scr' as well and nothing seems to be
working. Am I missing something simple, or is this not doable?
 
M

Mike Wahler

Frank M. said:
I'm trying to declare an array of pointers to structures so that I can make
the last element a NULL pointer. I figure that it would more easily allow
my library routines to know when to stop processing the array.

typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;


If I try to declare it like the following:

SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL
};

I get the error "Cannot convert 'int' to 'screen_disp *' " I've tried
various ways of declaring 'display_scr' as well and nothing seems to be
working. Am I missing something simple, or is this not doable?

Your array elements have pointer type. But you're trying
to initialize them with items which are not pointers (in
this case, they're structure objects).

SCR_DISP sd1 = {10, 5, "Test:"};
SCR_DISP sd2 = {15 10, "All Done"};

SCR_DISP *display_scr[] =
{
&sd1,
&sd2,
NULL
};


Or perhaps first creating an array of 'SCR_DISP' objects
would be more suitable:

SCR_DISP arr[] =
{
{10, 5, "Test:"},
{15, 10, "All Done"}
};

SCR_DISP *display_scr[] =
{
arr,
arr + 1,
};

If you have a function that iterates through the
array of pointers to get at the struct objects,
note that you could instead have it go through the
array of 'SCR_DISP' objects instead, getting the
address of each with the '&' operator, obviating
the need for the array of pointers.

void use_ptr_array(SCR_DISP **p)
{
while(*p)
; /* do stuff */
}

void use_array_directly(SCR_DISP *array)
{
while(p)
; /* do stuff */
}


I can't really offer any more specific advice without
knowing what you're trying to accomplish.

If
HTH,
-Mike
 
K

Kenneth Brody

Frank M. said:
I'm trying to declare an array of pointers to structures so that I can make
the last element a NULL pointer. I figure that it would more easily allow
my library routines to know when to stop processing the array.

typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;

If I try to declare it like the following:

SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL
};

I get the error "Cannot convert 'int' to 'screen_disp *' " I've tried
various ways of declaring 'display_scr' as well and nothing seems to be
working. Am I missing something simple, or is this not doable?

The syntax you're using is good for declaring an array of the struct, but
not an array of pointers to the struct. For that, you need something like:

=====

SCR_DISP mydisp[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" }
};

SCR_DISP *display_scr[] = { &mydisp[0], &mydisp[1], NULL };

=====

Remember, you are declaring an array of pointers, so you need to initialize
it with pointers.

Another possibility is to fill the last entry in an array with an invalid
value indicating the end. In your particular struct, sd_buff==NULL may
suffice, and simply use an array, rather than an array of pointers:

SCR_DISP display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
{ 0, 0, NULL }
};

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
M

Mike Wahler

Mike Wahler said:
Or perhaps first creating an array of 'SCR_DISP' objects
would be more suitable:

SCR_DISP arr[] =
{
{10, 5, "Test:"},
{15, 10, "All Done"}
};

SCR_DISP *display_scr[] =
{
arr,
arr + 1,

Oops, forgot the:

NULL

-Mike
 
J

Jens.Toerring

Frank M. said:
I'm trying to declare an array of pointers to structures so that I can make
the last element a NULL pointer. I figure that it would more easily allow
my library routines to know when to stop processing the array.
typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;

If I try to declare it like the following:
SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL
};
I get the error "Cannot convert 'int' to 'screen_disp *' " I've tried
various ways of declaring 'display_scr' as well and nothing seems to be
working. Am I missing something simple, or is this not doable?

The problem is that you try to initialize pointers with someting that
you can only use to initialize "real" structures:

{ 10, 5, "Test:" }

but which isn't a pointer to a structure of type 'screen_disp' but a
set of data that can be use to initialise such a structure. So what
you're doing here is mixing the syntax for initialisation of pointers
(NULL) with the syntax for the initialisation of structures. It's like
trying to use

int *p[ ] = { 1, 42, NULL };

to make p[0] to point to a memory location were the value 1 is stored
(and not set the pointer p[0] to 1, but which is what you actually tell
the compiler to do that way) and thus the compiler complains. So your
SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL

will tell the compiler to set the pointer disp_src[0] to the value 10
(and warns you that this is a dangerous conversion - are you sure you
are using a C and not a C++ compiler, since C compilers usually don't
have much qualms about doing such conversions unless you ask them to
be picky and even then only give you a warning but not an error?),
disp_scr[1] to the value 5, disp_scr[2] to be identical to the pointer
to the string literal "Test:" etc., ending up with an array of 7 poin-
ters - which rather obviously isn't what you want.

The bad news is that what you obviously want to do can't be done that
way. You must create some instances of the structures you want pointers
to and then set up your array of pointers to point to them. I guess you
are coming from a language like Perl were you can create "anonymous"
arrays or hashes etc. on the fly, but that's not something you can do
in C - with the exception of string literals, that's the only place I
can think of at the moment where you can do something like

char *my_strs[ ] = { "abc", "def", NULL };

but that's special because the '"abc"' is a pointer to an (immutable!)
instance of that string and that doesn't work with anyting else.

Regards, Jens
 
F

Frank M.

Mike Wahler said:
Or perhaps first creating an array of 'SCR_DISP' objects
would be more suitable:

SCR_DISP arr[] =
{
{10, 5, "Test:"},
{15, 10, "All Done"}
};

SCR_DISP *display_scr[] =
{
arr,
arr + 1,
};

If you have a function that iterates through the
array of pointers to get at the struct objects,
note that you could instead have it go through the
array of 'SCR_DISP' objects instead, getting the
address of each with the '&' operator, obviating
the need for the array of pointers.

void use_ptr_array(SCR_DISP **p)
{
while(*p)
; /* do stuff */
}

void use_array_directly(SCR_DISP *array)
{
while(p)
; /* do stuff */
}

That's just it. I need to iterate through the array to display the
elements. I tried to use the array directly, but that doesn't seem to work.
It goes on forever.

typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;

void quick_screen(SCR_DISP *display_scr)
{
while (display_scr)
{
gotoxy(display_scr->sd_col, display_scr->sd_row);
printf("ROW:%d COL:%d Buff:[%s]",
display_scr->sd_row,
display_scr->sd_col,
display_scr->sd_buff);
display_scr++;
}
return;
}

int main()
{
SCR_DISP display_scr[] =
{
{ 15, 5, "Test 1" },
{ 16, 6, "Test 2" },
{ 99, 99, "All Done" }
};

quick_screen(display_scr);
return 0;
}

The {99, 99, "All Done"} entry is what I am currently checking for in my
loop (as my invalid last entry). I was just hoping to be able to rid myself
of this last element since I now have lots of these structures defined all
over the place for drawing certain things to the screen. Is there any way
to do this correctly, or do I have to resort to creating an array of
pointers to these structures and then setting the last pointer to be NULL ?
 
A

Al Bowers

Frank said:
That's just it. I need to iterate through the array to display the
elements. I tried to use the array directly, but that doesn't seem to work.
It goes on forever.

typedef struct screen_disp
{
int sd_row;
int sd_col;
char *sd_buff;
} SCR_DISP;

void quick_screen(SCR_DISP *display_scr)
{
while (display_scr)
{
gotoxy(display_scr->sd_col, display_scr->sd_row);
printf("ROW:%d COL:%d Buff:[%s]",
display_scr->sd_row,
display_scr->sd_col,
display_scr->sd_buff);
display_scr++;
}
return;
}

There are several ways you can tackle this problem. One way is
to do as your original post; use a NULL. I favor to enclose an array
of the struct pointers which keeps changing in elements along
with a variable that keeps count of the current count. Then you
write functions that passes a pointer of this datatype ot functions
that will manipulate it. These functions can use the count variable
to determine the size of the array if it is needed.

Example:

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

#define STRS_SZ 16

typedef struct screen_disp
{
int sd_row;
int sd_col;
char sd_buff[STRS_SZ];
} SCR_DISP;

typedef struct SCR_DISP_ARR
{
SCR_DISP **disp;
size_t cnt;
} SCR_DISP_ARR;

typedef int (*CMP)(const void *v1, const void *v2);

int AddSCR_DISP_ARR(SCR_DISP_ARR *p, int row, int col,
const char *buff);
void FreeSCR_DISP_ARR(SCR_DISP_ARR *p);
void SortSCR_DISP_ARR(SCR_DISP_ARR *p,CMP cmp);
void PrintSCR_DISP_ARR(SCR_DISP_ARR *p);
int cmp_buff(const void *v1, const void *v2);

int main(void)
{
SCR_DISP_ARR test = {NULL};

AddSCR_DISP_ARR(&test,3,5,"Gamma");
AddSCR_DISP_ARR(&test, 5,7,"Alpha");
AddSCR_DISP_ARR(&test,7,9,"Beta");
puts("\t\tEXAMPLE OF SORTING BY AN ARRAY OF POINTERS\n");
puts("\tThe array unsorted:");
PrintSCR_DISP_ARR(&test);
puts("\n\tThe array sorted by buff:");
SortSCR_DISP_ARR(&test,cmp_buff);
PrintSCR_DISP_ARR(&test);
FreeSCR_DISP_ARR(&test);
return 0;
}

int AddSCR_DISP_ARR(SCR_DISP_ARR *p, int row, int col,
const char *buff)
{
SCR_DISP **tmpp;

if((tmpp = realloc(p->disp,(p->cnt+1)*sizeof *tmpp)) == NULL)
return 0;
if((tmpp[p->cnt] = malloc(sizeof **tmpp)) == NULL)
return 0;
p->disp = tmpp;
strncpy(p->disp[p->cnt]->sd_buff,buff,STRS_SZ);
p->disp[p->cnt]->sd_buff[STRS_SZ-1] = '0';
p->disp[p->cnt]->sd_row = row;
p->disp[p->cnt++]->sd_col = col;
return 1;
}

void FreeSCR_DISP_ARR(SCR_DISP_ARR *p)
{
size_t i;

for(i = 0;i < p->cnt;i++)
free(p->disp);
free(p->disp);
p->disp = NULL;
p->cnt = 0;
return;
}

void SortSCR_DISP_ARR(SCR_DISP_ARR *p,CMP cmp)
{
qsort(p->disp,p->cnt,sizeof *p->disp,cmp);
return;
}

void PrintSCR_DISP_ARR(SCR_DISP_ARR *p)
{
size_t i;

for( i = 0; i < p->cnt;i++)
printf("%d) row: %d col: %d buff: \"%s\"\n",
i+1,p->disp->sd_row,p->disp->sd_col,
p->disp->sd_buff);
return;
}

int cmp_buff(const void *v1, const void *v2)
{
SCR_DISP * const*e1 = (SCR_DISP * const*)v1;
SCR_DISP * const*e2 = (SCR_DISP * const*)v2;

return strcmp((*e1)->sd_buff,(*e2)->sd_buff);
}
 
D

Dave Thompson

Frank M." wrote: said:
typedef struct screen_disp { <snip> } SCR_DISP;
SCR_DISP *display_scr[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" },
NULL
};

I get the error "Cannot convert 'int' to 'screen_disp *' " I've tried
various ways of declaring 'display_scr' as well and nothing seems to be
working. Am I missing something simple, or is this not doable?

The syntax you're using is good for declaring an array of the struct, but
not an array of pointers to the struct. For that, you need something like:

=====

SCR_DISP mydisp[] =
{
{ 10, 5, "Test:" },
{ 15, 10, "All Done" }
};

SCR_DISP *display_scr[] = { &mydisp[0], &mydisp[1], NULL };
Or in C99 or 'ganuck' (GNU C, the language compiled by GCC):
SCR_DISP * display_scr [] = {
&(SCR_DISP){ 10, 5, "Test:" },
&(SCR_DISP){ 15, 10, "All Done" },
NULL };

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top