Accessing members of structs in a list in C - c

I have been working through the exercises in K&R on my quest to learn C, and I've hit a strange problem. I wrote a program to count words, characters, and lines in a file, then draw a histogram displaying the count for each. Everything worked well until I tried to make my code a little more reusable with a struct. My struct is as follows:
struct category {
char *name;
int namelen;
int count;
};
and it's values are assigned by a constructor function:
struct category createCat(char *name) {
struct category cat = {name, get_width(name), 0};
return cat;
}
and finally I have a list comprised of all the categories, as follows:
struct category catList[] = {words, lines, characters};
when I access the members of these structs by name, I have no issues. But if I try to access them in a loop, via catList[i].member, the member count always returns 0. the other two members, name and namelen, behave correctly withing the loop, and accessing count from outside the loops returns correctly. If anyone would be willing to help me understand what's going on I would greatly appreciate it.
if it is necessary, here is my full program:
#include <stdio.h>
#include <string.h>
int get_width(char* word) {
return 15 - strlen(word);
}
struct category {
char *name;
int namelen;
int count;
};
struct category createCat(char *name) {
struct category cat = {name, get_width(name), 0};
return cat;
}
int main () {
int c;
int inside_word;
int i;
int p;
struct category words = createCat("words");
struct category lines = createCat("lines");
struct category characters = createCat("characters");
struct category catList[] = {words, lines, characters};
while ((c = getchar()) != EOF) {
characters.count++;
if (c != '\n' && c != ' ' && c != '\t') {
putchar(c);
if (!inside_word) {
inside_word = 1;
words.count++;
}
}
else {
if (inside_word)
printf("\n");
inside_word = 0;
if (c == '\n')
lines.count++;
}
}
printf("\n%d words, %d lines, %d characters\n",
words.count, lines.count, characters.count);
for (i = 0; i < 3; i++) {
printf("%s:%*s", catList[i].name, catList[i].namelen, " ");
printf("%d", catList[i].count);
for ( p = 0; p < catList[p].count; p++)
printf("#");
printf("\n");
}
return 0;
}

When you do this:
struct category catList[] = {words, lines, characters};
You are copying the 3 structs' data into the catList. So when you update the 3 structs by their names, the ones in the catList are different copies and would not be updated.
To resolve this, I would recommend using pointer types. There are two ways of doing this.
You can return a pointer in the createCat method.
struct category* createCat(char *name) {
struct category* cat = (struct category*) malloc(sizeof(struct category));
//...
return cat;
}
From this point on, always use pointer for storing. This is quite commonly used.
You can store the pointer in the array catList:
struct category *catList[] = {&words, &lines, &characters};
and when you use them in the loop, use like:
catList[i]->count++;

You are copying the words, lines, characters structures into your list.
But you do this before you process the data, so they never get updated.
If you want to maintain both sets of structures, you must update them in your loop:
words.count++;
catList[0].count++;
If you want to maintain a single set, delete the other. (Pretty much what you have now, except for the top and bottom.)
If you want them to share data, then use pointers, so the list (or the stand-alone variables) point to the other structure.

Related

Modify and print typedef'd array in C

I am learning to work with structures and this doubt come to me when doing one exercise with C.
I have this code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#define MAX_STRING 256
#define MAX_CHILD 2000
#define MAX_GIFTS 20
#define MAX_LINE 1024
typedef char String[MAX_STRING];
typedef char Line[MAX_LINE];
typedef struct {
String child_name;
int grade; //integer between 0 and 5
String gift_name;
int price; //price of the gift
} Data;
typedef struct {
String name;
int price;
bool received; //true if the child will get this gift
} Gift;
typedef Gift Gifts[MAX_CHILD];
typedef struct{
String name;
int grade;
Gifts asked; //gifts the child asked for
int n_asked;
} Child;
typedef Child Children[MAX_CHILD];
Data make_data (String line){
Data d;
sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
return d;
}
Child make_child(Data d) {
Child c;
strcpy(c.name, d.child_name);
c.grade = d.grade;
c.n_asked = 0;
return c;
}
Gift make_gift(Data d){
Gift g;
strcpy(g.name, d.gift_name);
g.price = d.price;
g.received = false;
return g;
}
int process(char file_name[]){
Line line;
FILE *f = fopen(file_name, "r");
while(fgets(line, MAX_LINE, f) != NULL){
make_data(line);
}
int fclose (FILE *f);
}
int main(){
process("data.txt");
return 0;
}
So this program receives a file text of this format:
John 4 Bike 200
Alice 3 Computer 800
Alice 3 Candy 10
Mike 5 Skate 100
and constructs the data in the function process.
The problem is, I want to store all the children in the array Children[ ] and to print it( print all the array or just something similar to Children[0], Children[1],etc). I have tried some ways but no success...as the array is of type Children and not char*. Even when I just do Children cs; I get segmentation fault. Is there a way I can accomplish this?
And my second question is, initially I had #define MAX_CHILD 20000 and when I tried to compile I got an error saying "size of array ‘Children’ is too large". Why does this happen? I see it doesn't happen to Gifts, but happens to Children because the struct Child has a Gifts type as on the members, which means it requires more space.
Any help appreciated.
the use of the typedef's (and so on)
instead of just writing the code out where it is needed
is unneeded (and distracting) and mis-leading and
makes the code much more difficult to follow.
This function:
Data make_data (String line)
{
Data d;
sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
return d;
}
has several problems:
1) the parameter list will cause the compiler to 'set aside' enough room
for the String struct,
invoke a memcpy() to copy the String struct
to that 'set aside' memory from the callers' memory
Then copy the 'set aside' memory to the called functions' stack
That 'set aside' memory will never be used for anything else
The stack will be cluttered with the contents of the String struct
until the function returns
such activity is a real 'bear' to debug
2) the returned value from sscanf() needs to be checked
to assure that all 4 conversion operations were successful
3) the function return is a instance of the Data struct.
This will cause the compiler to 'set aside' enough room
for the Data struct.
that 'set aside' memory will never be used for anything else
invoke a memcpy() to copy the Data struct from the stack
to the 'set aside' memory
then perform the return from the function
then the compiler will cause the caller to
invoke memcpy() to copy the Data struct
from the 'set aside' memory to the caller's Data struct area.
such activity is a real 'bear' to debug.
The function should be written more like this:
int make_data (String *pLine, Data* pData)
{
int returnValue = 1; // initialize to indicate function successful
if( 4 != sscanf(pLine," %s %d %s %d",
pData->child_name,
&pData->grade,
pData->gift_name,
&pData->price) )
{ // then sscanf failed
perror( "sscanf failed for Line" );
returnValue = 0; // indicate to caller that function failed
} // end if
return( returnValue );
} // end function: make_data
and the caller(s) of this function should be adjusted accordingly
the make_gift() function has the same passed parameter
and returned parameter problems.
The problem is, I want to store all the children in the array
Children[ ] and to print it( print all the array or just something
similar to Children[0], Children[1],etc).
to store:
static Children cs;
size_t nc = 0; // number of children
while (fgets(line, MAX_LINE, f))
{
#include <search.h>
Data d = make_data(line);
Child c = make_child(d);
Child *cp = lsearch(&c, cs, &nc, sizeof c, (int (*)())strcmp);
cp->asked[cp->n_asked++] = make_gift(d);
}
to print:
int i, j;
for (i = 0; i < nc; ++i)
{
printf("%s (grade %d) asked for %d:\n",
cs[i].name, cs[i].grade, cs[i].n_asked);
for (j = 0; j < cs[i].n_asked; ++j)
printf("\t%s\t%d\n", cs[i].asked[j].name, cs[i].asked[j].price);
}
(We cannot simply print an aggregate type object - we have to print the individual elements.)

How to parse the given string into array of structure variable

P|20131120|20131120
C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|
C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|
C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|
C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|
P|20131121|20131121
C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|
C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|
Above is the message coming from one server as a single string. Now i want to parse it and store in a structure for the processing in C language.
Here for one P(Period) row, there can be many C(Class) rows. '|' is field delimiter which should be ignored while storing into the structure. Here the number of C(Class) rows are not fixed for a P.
Can anybody suggest me in C, how should i declare the Structures and parse and store these fields into it. As per my guess i will have to declare the structure array at run time for class(C) rows because it is not fixed. One thing is fixed: P(Period) row size is always 17 byte (or charector) excluding pipe(|) and C(Class) row size is 61 character excluding pipe(|. Dear All, can please anybody help me in C logic or code.
There are multiple parsing levels for this string
Use token as P/C for doing the first level of filtering
Use token as | as second level of filtering ( Inside which youi have H/Y etc which you need to take into consideration as well while copying it to structure members).
Accordingly you can have structure declartion .
You can visit this article strtok usage
Here you go -
struct node{
char startChar, endChar;
float numArr[8];
struct node *next;
}
struct headerNode{
int num1, num2;
struct node *first;
}
After that you can make use of
createList() //create a blank list with header node.
createNode() //a C node everytime you need it.
Rest is merely parsing the string.
I hope this will help.
struct c_struct
{
char c_content[61];
struct c_strcut *next_c_strcut; //pointer to next class
};
struct PC_struct
{
char p_content[17];
struct c_struct *c_head; // pointer to first node
struct PC_struct *PC_struct; // pointer to next pc
};
#include <stdio.h>
#include <string.h>
#define MAX_CLASSES 100
#define MAX_PERIODS 100
struct Class{
char a, i;
float b,c,d,e,f,g,h,j;
};
struct Period{
char date1[10], date2[10];
struct Class classes[MAX_CLASSES];
};
struct Period periods[MAX_PERIODS];
int main(void){
//use sscanf to parse the data
//for example, (assuming data is in char *s),
//sscanf(s, "P|%s|%s\n", periods[0].date1, periods[0].date2);
return 0;
}
The most critical part is safely parsing the input, after that, interpretation, validation and organization of the pre-structured data is a breeze, I made only the hard part (input handling) below
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *data =
"P|20131120|20131120\n"
"C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|\n"
"C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|\n"
"C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|\n"
"C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|\n"
"\n"
"P|20131121|20131121\n"
"C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
"C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
"C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
"C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
;
struct columns
{
char *cols[12]; /* 16 pointers */
} rows[100]; /* bss, all zero */
#define N_COLS (sizeof(struct columns)/sizeof(char*))
#define N_ROWS (sizeof(rows)/sizeof(struct columns))
int main(void)
{
char *rowsdata, *s;
char **curcol = rows->cols;
char **lastcol = rows->cols + N_COLS;
int row, i;
rowsdata = s = strdup(data);
if (rowsdata == 0) {
perror("strdup");
exit(1);
}
for (row=0; row < N_ROWS; s++) {
if (*s == '|') {
*s = 0;
if (++curcol == lastcol) {
puts("error: too much columns");
exit(1);
}
} else if (*s == '\n') {
*s = 0;
row++;
curcol = (rows + row)->cols;
lastcol = (rows + row)->cols + N_COLS;
} else if (*curcol == 0) {
*curcol = s;
} else if (*s == 0) break;
}
/* do your logic here
*/
for (i=0; i<row; i++) {
curcol = (rows + i)->cols;
lastcol = (rows + i)->cols + N_COLS;
while (*curcol && curcol < lastcol) {
printf("[%s]", *curcol);
curcol++;
}
printf("\n");
}
/* free rowsdata only when done with rows
*/
free(rowsdata); rowsdata = 0;
return 0;
}
the code above relies heavily on pointer arithmetic
*edit: rename from 'cols' to 'rows' and 'cells' to 'cols', makes more sense

Creating a dynamic custom array of nested structs in C

I'm trying to create the following array:
"Fruits", 25, {
{"Apple", 2},
{"Grapes", 13},
{"Melon", 10}
}
"Meats", 40, {
{"Beef", 9},
{"Chicken", 27},
{"Pork", 4}
}
...
Feels like there's a more elegant way of doing what I got so far. Any feedback/samples on how to create this structure more efficient given the input struct would be appreciated.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Product {
char *name;
int qty;
} Prods;
typedef struct Category {
char *name;
int qty;
int prods_count;
Prods *prod;
} Cats;
typedef struct Inventory {
Cats *cat;
int cats_count;
} Inv;
struct tmp_input {
char name[12];
int qty;
char cat[12];
};
// return index if found
int in_array(Inv *inv, char *k) {
int i;
if (inv->cats_count == 0)
return -1;
for (i = 0; i < inv->cats_count; i++) {
if (strcmp (k, inv->cat[i].name) == 0) return i;
}
return -1;
}
int main () {
int i, j, exists = 0;
// temp struct.
struct tmp_input items[] = {
{"Apple", 2, "Fruit"}, {"Coke", 10, "Drink"}, {"Pork", 4, "Meat"},
{"Beef", 9, "Meat"}, {"Chicken", 27, "Meat"}, {"Melon", 10, "Fruit"},
{"Tea", 3, "Drink"}, {"Coffee", 20, "Drink"}, {"Grapes", 13, "Fruit"}
};
size_t len = sizeof (items) / sizeof (struct tmp_input);
Inv *inven = malloc(sizeof(Inv));
inven->cats_count = 0;
inven->cat = calloc(1, sizeof(Cats));
for (i = 0; i < len; i++) {
exists = in_array(inven, items[i].cat);
// category does not exist
if (exists == -1) {
inven->cat = realloc(inven->cat, sizeof(Cats) * (inven->cats_count + 1));
inven->cat[inven->cats_count].name = strdup(items[i].cat);
inven->cat[inven->cats_count].qty += items[i].qty;
inven->cat[inven->cats_count].prods_count = 1;
inven->cat[inven->cats_count].prod = calloc (1, sizeof (Prods));
inven->cat[inven->cats_count].prod->name = strdup (items[i].name);
inven->cat[inven->cats_count].prod->qty = items[i].qty;
inven->cats_count++;
}
// category found
else {
inven->cat[exists].qty += items[i].qty;
int size = inven->cat[exists].prods_count + 1;
inven->cat[exists].prod = realloc(inven->cat[exists].prod, sizeof(Prods) * (size));
inven->cat[exists].prod[size - 1].name = strdup (items[i].name);
inven->cat[exists].prod[size - 1].qty= items[i].qty;
inven->cat[exists].prods_count++;
}
}
for (i = 0; i < inven->cats_count; i++) {
printf("%3d %s\n", inven->cat[i].qty, inven->cat[i].name);
for (j = 0; j < inven->cat[i].prods_count; j++) {
printf("%3d %s\n", inven->cat[i].prod[j].qty, inven->cat[i].prod[j].name);
}
}
return 0;
}
You aren't allocating any memory for the Prod array.
Something like
...
if (exists == -1) {
inven->cat = realloc(inven->cat, sizeof(Cats) * (inven->cats_count + 1));
inven->cat[inven->cats_count].name = items[i].cat;
inven->cat[inven->cats_count].qty += items[i].qty;
// Allocate memory for 1 product
inven->cat[inven->cats_count].prods_count = 1;
inven->cat[inven->cats_count].prod = malloc (sizeof (Prods));
// Now allocate space and copy the name
inven->cat[inven->cats_count].prod->name = strdup (items[i].name + 1);
inven->cats_count++;
}
...
I will leave it to you to handle the case where there are more than 1 product in a category, where you'll need to reallocate the memory again.
Another error is that you need to allocate and copy the category name
inven->cat[inven->cats_count].name = items[i].cat;
should be replaced by
inven->cat[inven->cats_count].name = strdup (items[i].cat);
This is because the items array does not exist outside of this function, so if you just do
inven->cat[inven->cats_count].name = items[i].cat;
then after you leave this function, invent->cat[inven->cats_count].name will point to garbage memory.
A final suggestion would be to split each structure into a function that handles creation of it, just to clean up the code.
--- edit to add comments on Abstract Data Types
Arrays are useful if you have data that you know you will be accessing via indices. If you don't know the index of the item you want (as in this case), an array is less useful.
Unlike other comments, I don't think using a Linked List really gives you anything useful. Linked Lists are useful when you need to walk sequentially through all the items, without really caring where they are in the list. It seems to me that the most common use case for a system like you are creating is searching: Do we have any Fruit in stock? Add 10 cases of Coke to the inventory... those sorts of things.
Also, you only want a single entry for each category/product. You don't want 3 Fruit categories in the data. Both arrays and linked lists don't really have any restrictions on adding the same structure multiple times. This means that every time you'll need to check the whole list to see if you need to add the new structure.
For that reason, I'd certainly make both the Categories and products arrays into hashtables (or called a dictionary in some languages) that map name -> structure. This will speed up your search as you don't have to search the entire dataset every time and will prevent you from adding the same structure multiple times.
Wikipedia article on Hashtables: http://en.wikipedia.org/wiki/Hashtable
Here's an example of how to set up the structures dynamically (simpler than a linked list, but not as flexible).
typedef struct Product {
char *name;
int qty;
} Prods;
typedef struct Category {
char *name;
int qty;
int prods_count;
Prods *prod; // dynamic array of Products
} Cats;
The structures as they were.
struct Category categ[10];
An arbitrary number of categories, for now take categ[0] for 'Fruits'.
Next dynamically create an array of 10 product structures:
Prods *prod_array = malloc(sizeof(Prods) * 10); // i.e. prod_array[0] to [9]
Now just store the array in the category structure:
categ[0].prod = prod_array;
categ[0].prods_count = 10;
If you need to access the product name, it's just: categ[i].prod[j].name
Now, if you need another 10 products, you can just use realloc to increase the size of the array, and update its count.
Put all these things in functions, and the code isn't too complex.

function searching in an array of structures - stop condition unknown

The following program stores every word and then prints them with a number of occurrences.
Global typedef declaration:
typedef struct {
char * word;
int occ;
}
words;
words *data=NULL;
I have a problem with the search function. I've created a function returning int that looks like this: (max is the constantly updated size of an array of structures, that's why I call search function after EOF is reached.)
int search(char *word,int max)
{
int i;
for(i=0; i<max; i++)
{
if(!strcmp(data[i].word,word)) return i;
}
return -1;
}
But I noticed I'm supposed to write a search function having that prototype:
struct abc *find(char *word)
So I've created the following code:
struct words *findword(char *word)
{
struct words *ptr;
for (ptr = data; ptr != NULL; ptr++) { /* IS THE STOP CONDITION OK? */
if (strcmp(word, ptr->word) == 0)
return ptr;
}
return NULL;
}
And I receive many errors during compilation:
reverse.c: In function ‘findword’:
reverse.c:73: warning: assignment from incompatible pointer type
reverse.c:73: error: increment of pointer to unknown structure
reverse.c:73: error: arithmetic on pointer to an incomplete type
reverse.c:74: error: dereferencing pointer to incomplete type
reverse.c: In function ‘main’:
reverse.c:171: error: ‘which’ undeclared (first use in this function)
reverse.c:171: error: (Each undeclared identifier is reported only once
reverse.c:171: error: for each function it appears in.)
make: * [reverse.o] Error 1
which is an int variable assigned to the return of my firstly written search function.
The error with which is easily fixed, but I don't know how to replace that (solution working with my base search function):
data[which].occ++;
How to fix it so that it'll work with my new approach to search?
EDIT
main() added:
int main(int argc, char **argv)
{
char *word;
words *temp;
int c,i,num;
/*int which;*/
FILE *infile;
if(argc!=2) {}
if((infile=fopen(argv[1],"r"))==NULL) {}
num=0;
while(1)
{
c=fgetc(infile);
if(c==EOF) break;
if(!isalpha(c)) continue;
else ungetc(c,infile);
word=getword(infile);
word=convert(word);
/*which=search(word,num);*/
if(findword(word))
{
if(!(temp=realloc(data,sizeof(words)*(num+1))))
{}
else
data=temp;
data[num].word=strdup(word);
data[num].occ=1;
num++;
}
else
data[which].occ++;
free(word);
}
sort(num-1);
for(i=0;i<num;i++)
{}
free(data);
if(fclose(infile))
{}
return 0;
}
I've left {} for the irrelevant pieces of code eg. error handling.
EDIT2
The things I'm asking for above, are fixed. However, I get a seg fault now.
I'll give a link to the whole code, I don't want to put it in an edited post since it'd create a big mess. Seg fault is caused by lines 73 and 152 (strcmp is not working somehow). Hope that full code will be easier to understand.
FULL CODE
The problems are with your findword function, lets go through all the lines
struct words *ptr;
This is not what you ment to do. The typedef you used in defining the structure allows you to not need to write struct anymore. This is why you're getting the error: reverse.c:73: error: increment of pointer to unknown structure. What you want is just:
words *ptr;
Next, the loop:
for(ptr=data; //This is fine, you're assigning your local ptr to the global data. I assume that's something valid
ptr != NULL; //That could OK too... we can loop while ptr is not NULL
ptr++) //This line makes no sense...
You may want to look up how for loops work again, the point is you're incrementing something until it hits a condition. ptr++ will move where you're pointing too, so you'll no longer be pointing to your structure.
I need to see your main() function to understand what you're trying to accomplish, but based on the prototype you have to follow, I think the easiest solution would be something like:
void main()
{
// init your vars
bool more_words_to_add = true;
words *ptr = NULL;
int i;
// populate your array of words
while(more_words_to_add) {
for(i = 0; i<max; i++) {
if(ptr = findword("word")) //if we find the word
ptr->occ++; //increment the number of times we found it
else {
//I don't know what you want to do here, it's not clear what your goal is.
//Add the new word to your array of words and set occ to 1,
//then increment max because there's one more word in your array?
}
}
//get the next word to fine, or else set more_words_to_add = false to break
}
}
If this type of solution is what you're looking to do, then you can adjust your findwords function to be very simple:
struct words *findword(char *word)
{
words *ptr = data;
if (strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
EDIT: For your new error I suspect the problem is with your memory allocation, see this short example of using your structure:
words *findword(char *word)
{
words *ptr = data;
if(strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
int main(){
words *ptr;
data = realloc(data, sizeof(words));
data->word = "hello"; //DO NOT SKIP THESE LINES
data->occ = 0; //DO NOT SKIP THESE LINES
if(ptr = findword("hello")) {
ptr->occ++;
printf("I found %d %s's\n",ptr->occ, ptr->word);
}
}
mike#linux-4puc:~> ./a.out
I found 1 hello's
You can see here that you need to alloc some memory for the global structure then you can store data in it and pass pointers to it.
EDIT 2:
Your main() code does this:
if((ptr = findword(word)))
{
//do stuff
}
else
ptr->occ++;
That's not going to work because if findword() fails it returns NULL, so in the if check ptr is set to NULL, then in the else you're trying to deference NULL. If (and keep in mind I'm not really reading your logic so this is up to you) you really want to increment ptr->occ if a word is not found then you want this instead:
if(findword(word))
{
ptr = findword(word);
//do stuff
}
else
ptr->occ++; //increments the current ptr's occ, no new ptr was assigned.
for (ptr = data; ptr != NULL; ptr++) {
/* IS THE STOP CONDITION OK? */
No. Your pointer just keeps getting incremented. The only thing that would make it NULL in that code is integer overflow. You could look at what it points to, and see if that is NULL, IF you preset the data area to 0's:
#define NUM_WORDS 100
data = calloc(NUM_WORDS,sizeof(words));
Or
#define NUM_WORDS 100
int bytes = NUM_WORDS * sizeof(words);
data = malloc(bytes);
memset(data,0,bytes);
....
for (ptr = data; ptr->word != NULL; ptr++) {
If you don't want to preset the data area to 0 then you will have to pass the current amount of structs currently held in the data area to your function in order to know how much to loop.
There's no such thing as struct words in your program; there's an unnamed struct type, and a typedef words to that type. Either use struct words or words consistently.
You'll then need to replace
data[which].occ++;
with
result->occ++;
where result is the return value from your new search function.

Struct member corrupted after passed but not after passed again

I'm having some very strange bug in my ANSI C program.
I'm using debugger and I've observed that 'size' variable is corrupted in function 'doSthing.' Outside of 'doSthing' 'size' got a proper value, but inside 'doSthing' I've got a value nothing similar to what it should be, possibly some random data. This would be not be such a mystery but...
In 'doAnotherThing' which is called from 'doSthing' I get the proper value again. I suppose if it passes the correct value, it is not corrupted anyway, am I wrong? But then why does it have a different value?
The pointer in struct does not change inside the functions.
Memory is allocated for both oTV and oTV->oT.
I really don't see what's happening here...
typedef struct{
ownType *oT[] /* array of pointers */
int size;
} ownTypeVector;
void doSthing(ownTypeVector* oTV);
void doAnotherThing(ownTypeVector* oTV);
void doSthing(ownTypeVector* oTV)
{
...
doAnotherThing(oTV);
...
}
Thanks for your comments, I collected all the code that contains control logic and data structures so that it compiles. It runs on in an embedded systems, that can receive characters from multiple sources, builds strings from it by given rules and after the strings are ready, calls a function that needs that string. This can also be a list of functions. This is why I have function pointers - I can use the same logic for a bunch of things simply by choosing functions outside the 'activityFromCharacters' function.
Here I build a data structre with them by adding A-s, B-s and C-s to the AVector.
Of course every one of these separate sources has their own static strings so that they do not bother each other.
The problem again in the more detailed version of the code:
'aV->size' has got a proper value everywhere, except 'handleCaGivenWay.' Before it gets calles, 'aV->size' is ok, in 'addA' 'aV->size' is ok, too. After leaving 'handleCaGivenWay' it is ok again.
#define NUMBER_OF_AS 1
#define NUMBER_OF_BS 5
#define NUMBER_OF_CS 10
typedef struct{
char name[81];
} C;
typedef struct{
C *c[NUMBER_OF_CS]; /* array of pointers */
int size;
int index;
} B;
typedef struct{
B *b[NUMBER_OF_BS]; /* array of pointers */
char name[81];
int size;
} A;
typedef struct{
A *a[NUMBER_OF_AS]; /* array of pointers */
int size;
} AVector;
typedef struct {
char *string1;
char *string2;
} stringBundle;
typedef struct{
void (*getCharacter)(char *buffer);
void (*doSthingwithC)(stringBundle* strings,AVector* aV);
AVector* aV;
} functionBundle;
void getCharFromaGivenPort(char *buffer)
{
//...
}
void addA(AVector * aV, stringBundle* strings)
{
aV->a[aV->size]->size = 0;
++aV->size;
int i = 0;
if(strlen(strings->string2) < 81)
{
for(i;i<81;++i)
{
aV->a[aV->size-1]->name[i] = strings->string2[i];
}
}
else {report("Too long name for A:");
report(strings->string2);}
}
void handleCaGivenWay(stringBundle* strings,AVector* aV)
{
A* a;
a = NULL;
if(aV->size) { a = aV->a[aV->size-1]; }
switch(1)
{
case 1: addA(aV,strings); break;
case 2: //addB()...
default: if (a && aV->size)
{ //addC(a->thr[a->size-1],c);
}
else report("A or B or C invalid");
break;
}
//handleCaGivenWay
}
void activityFromCharacters(stringBundle* strings,functionBundle* funcbundle)
{
/* some logic making strings from characters by */
/* looking at certain tokens */
(* funcbundle->doSthingwithC)(strings,funcbundle->aV);
}
//activityFromCharacters
AVector* initializeAVector(void)
{
AVector* aV;
if (NULL == (aV = calloc(1,sizeof(AVector))))
{ report("Cannot allocate memory for aVector."); }
int i = 0;
int j = 0;
int k = 0;
for(i; i < NUMBER_OF_AS; ++i)
{
if (NULL == (aV->a[i] = calloc(1,sizeof(A))))
{ report("Cannot allocate memory for As."); }
aV->a[i]->size = 0;
aV->a[i]->name[0] = 0;
for(j; j < NUMBER_OF_BS; ++j)
{
if (NULL == (aV->a[i]->b[j] = calloc(1,sizeof(B))))
{ report("Cannot allocate memory for Bs."); }
aV->a[i]->b[j]->size = 0;
for(k; k < NUMBER_OF_CS; ++k)
{
if (NULL == (aV->a[i]->b[j]->c[k] = calloc(1,sizeof(C))))
{ report("Cannot allocate memory for Cs."); }
}
}
}
aV->size = 0;
return aV;
//initializeProgramVector
}
int main (void)
{
AVector* aV;
aV = initializeAVector();
while(1)
{
static stringBundle string;
static char str1[81];
static char str2[81];
string.string1 = str1;
string.string2 = str2;
functionBundle funcbundle;
funcbundle.getCharacter = &getCharFromaGivenPort;
funcbundle.doSthingwithC = &handleCaGivenWay;
funcbundle.aV = aV;
activityFromCharacters(&string,&funcbundle);
}
//main
}
your code shows that it hasn't any error...
But i think you are doing mistake in getting the value of size in doSthing function.
you are printing there its address. so concentrate on some pointer stuff..
Try printing the oTV->size just before the call and as the first statement in doSthing function. If you get the correct value in both print, then the problem is with the function doSthing. Problem could be better understood if you've shown the code that calls doSthing.
Searched a long time to find this. I found 2 problems, but dont know what exactly you are trying to accomplish so i cannot tell for certain that the fix'es i propose are what you intend.
typedef struct{
A *a[NUMBER_OF_AS]; /* array of pointers */
int size;
} AVector;
// and in addA():
aV->a[aV->size]->size = 0;
First: You are inlining the array of pointers in the struct. What i think what you want and need is a pointer to a pointer array so that it can grow which is what you want in addA() i think. The line from addA() aV->a[aV->size]->size = 0; does not communicate your intention very well but it looks like you are trying to change the value beyond the last entry in the array and since it is inlined in the struct it would result to the separate field size by pure coincidence on some alignments; this is a very fragile way of programming. So what i propose is this. Change the struct to contain A** a; // pointer to pointer-array, malloc it initially and re-malloc (and copy) it whenever you need it to grow (in addA()).

Resources