C program crashes when trying to refer to struct array - c

I'm trying to make a simple database program, but when I get to this line
int idSearch(product* itens, int id) {
int i = 0;
for(i; i < size; i++) {
if(itens[i].id == id) //<=== This line
return i;
}
return ITEM_NOT_FOUND;
}
the program stops responding.
size is set as a global variable in the begining of the program
FILE* flog;
FILE* db;
FILE* sizef;
int size = 100;
this function is called by
void newProduct(product* itens, char name[64], int id, float price) {
int pos = idSearch(itens, 0);
if(idSearch(itens, id) != ITEM_NOT_FOUND) {
printf("Erro, o produto ja existe");
return;
}...
items is defined as
itens = (product*) calloc(sizeof(product), size);
and product is a struct defined as such
typedef struct{
char name[64];
int id;
float price;
int amount;
} product;
Firstly I thought the problem was that I was not using the -> operator, but when I tried the compiler says its not right.
I'm using Code::Blocks with GCC compiler on a Windows 7 x64
**EDIT: the whole code can be found here: http://hastebin.com/atulajubar.tex
Hope to hear answers soon, Thanks in advance

**EDIT: You're calling calloc() wrong. The signature is: void *calloc(size_t nelem, size_t elsize);
You're giving it the size first, then the number of elements. Switch that around and see if your problem is resolved.
Also, when calling (AFTER THE FIX:) itens = (product*) calloc( size, sizeof(product) );,
it's important to check to see that itens is not NULL after doing this. If calloc isn't able to give you back the right amount of memory, it returns a NULL pointer I believe. Check this, because if you're getting NULL back, that's your issue.
One good, easy, portable way of checking that would be:
if(!itens){
fprintf(stderr, "Error! Could not allocate memory!\n");
exit(1);
}
Also, as WhozCraig suggested, please make sure your code contains #include <stdlib.h>, a requirement of calloc() as per its man page.

This is wrong:
if((db = fopen(DB_PATH, RB))==NULL)
{
if((db = fopen(DB_PATH, RWB))==NULL)
{
exit(1);
}
else
{
itens = (product*) calloc(sizeof(product), size);
fwrite(itens, sizeof(product), size, db);
rewind(db);
}
}
fread(itens, sizeof(product), size, db);
If you have a DB_PATH file in the current working directory the first fopen() will succeed and the items allocation will never take place. Only if the file is not found, but is then successfully created will items contain a valid allocation, assuming calloc worked.
That else condition should be removed:
// note calloc parameter order addressed.
itens = calloc(size, sizeof(product));
if (itens == NULL)
{
perror("Failed to allocate items.");
exit(EXIT_FAILURE);
}
if((db = fopen(DB_PATH, RB))==NULL)
{
if((db = fopen(DB_PATH, RWB))==NULL)
exit(EXIT_FAILURE);
fwrite(itens, sizeof(product), size, db);
rewind(db);
}
fread(itens, sizeof(product), size, db);
There is a significant amount of error checking left to handle, but this needs to be addressed regardless.

Related

How can I save these struct to a binary file?

I have two structs I am aiming to save to a binary file.
typedef struct {
int height;
int width;
int resistance_count;
Resistance** resistances; //contains a list of resistance*.
} Breadboard;
typedef struct {
int start_cell_col;
int end_cell_col;
int cell_row;
float resistance_value;
} Resistance;
I am somewhat unsure how I should be going about saving them. Since I need to keep track of the "resistance_count" variable to know how many resistances I will be saving, I have to save the breadboard first. To do that my attempt has been as follows:
bool save_breadboard(char* filename, Breadboard* bb_pointer) {
errno_t error_code;
FILE* fp_board;
/* Opens board.bin to save the board struct on. */
error_code = fopen_s(&fp_board, filename, "wb");
if (error_code != 0) {
return false;
}
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
if (elements_written == 0) {
return false;
}
fclose(fp_board);
return true;
}
With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers. But I don't think it will cause problem when I eventually read from it.
To save resistances I'm running into problems. Here is what I do:
bool save_resistances(char* filename, Breadboard* bb_pointer) {
errno_t error_code;
FILE* fp_resistances;
/* Opens resistances.bin to save the array of resistance pointers on. */
error_code = fopen_s(&fp_resistances, filename, "wb");
if (error_code != 0) {
return false;
}
size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
bb_pointer->resistance_count, fp_resistances);
if (elements_written == 0) {
return false;
}
fclose(fp_resistances);
return true;
}
I am pretty sure that I will be saving the resistance pointer this way. I cannot check with binary files, but if I am would dereferencing the resistance pointer help?
size_t elements_written = fwrite(*bb_pointer->resistances, sizeof(Resistance),
^ bb_pointer->resistance_count, fp_resistances);
Any help in helping me understand reading/writing to binary files would be much appreciated.
You are getting close to the solution. Just a couple of things missing...
With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers [...]
Yeah, it is unnecessary. Indeed when reading back you will have to discard it and overwrite it with a valid value. I wouldn't bother finding strange ways of skipping the pointer. I'd suggest writing out a NULL pointer instead to avoid mistakes when re-reading the data by doing something like:
void *tmp = bb_pointer->resistances;
bb_pointer->resistances = NULL;
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
bb_pointer->resistances = tmp;
Now, coming to the part where you actually save all your structures, this is wrong:
size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
bb_pointer->resistance_count, fp_resistances);
And doing *bb_pointer->resistances is also wrong. You want to save each Resistance struct, but your ->resistances is an array of pointers, so (1) saving the pointers (bb_pointer->resistances) is obviously wrong and (2) trying to save the structs as if they were contiguous in memory (*bb_pointer->resistances) is also wrong. The only thing you can do is loop over the array and dereference every single pointer, saving it separately:
for (int i = 0; i < bb_pointer->resistance_count; i++) {
if (fwrite(bb_pointer->resistances[i], sizeof(Resistance), 1, fp_resistances) != 1) {
// handle error
return false;
}
}
Finally, remember that fwrite returns the number of elements written which should always be equal to the requested number, so in general you need to check for errors with res != count, not with res == 0:
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
if (elements_written != 1) {
return false;
}

Save struct with pointer members in file

I'm trying to save a struct into a .dat file and read it back in later.
struct myStruct{
char **one;
mytype **two;
mytype2 *three;
}
With an assigning function:
struct MyStruct get_struct() = {
char **pi = ...;
mytype **pa = ...;
mytype2 **po = ...;
MyStruct n = {pi, pa, po};
return n;
}
I originally tried to save this struct into a .dat file by doing this:
struct MyStruct s = get_struct();
myoutfile = fopen("file.dat", "w");
if (myoutfile == NULL) {
fprintf(stderr, "\nError opend file\n");
exit(1);
}
fwrite(&s, sizeof(struct MyStruct), 1, myoutfile);
fclose(myoutfile);
and read it back in with:
fread(&t, sizeof(struct MyStruct), 1, myinfile)
Now I learned, that this does not work (segmentation error), because I only save the location where the pointer points to, not the actual thing.
Now my question is, how can I do it properly? I have found some solutions for C++ but I need to stay in C.
EDIT:
Later on, I want to call a function which looks like this:
void work_with_struct(MyStruct s){
char ** xone = s.one;
mytype **xtwo = s.two;
mytype2 *xthree = s.three;
}
This post is related to this post, but as I could specify my mistake now, asking in a new post makes more sense to me.
As always in programming, you break up the task to smaller chunks, and break up smaller chunks to yet smaller chunks, until every chunk is easy.
int saveMyStruct (struct myStruct* myStruct, FILE* file) {
// what do I do here?!?!
// well it has three members
// so treat each one in sequence
int result;
result = saveStringArray(myStruct->one, file);
if (result >= 0)
result = saveMyTypeArray (myStruct->two, file);
if (result >= 0)
result = saveMyType (myStruct->three, file);
return result;
}
Note how the status is checked all the time. If you work with files, you need to check the status all the time.
What next? You need to write three functions mentioned above.
saveStringArray(char** stringArray, FILE* file)
{
// first save the length of the array, then save each individual string
int length = getStringArrayLength(stringArray);
int result = fwrite(&length, sizeof(length), 1, file);
if (result != 1)
return -1;
for (i = 0; i < length; ++i)
{
result = saveString(stringArray[i], file);
if (result < 0)
return -1;
}
return i;
}
And so on and so forth. I presume your array of pointers is NULL-terminated; if not, you need to have some other way to know its length.
Note how array length is always saved before array elements. This is because you will need to read your array later, and you will need to know where to stop. It will also be easy to allocate your array when you read it.

Code with nested struct — what's the right way to allocate memory?

I wrote this code (*pdata)->pProd = (Product*)malloc(sizeof(Product)*size1);
When I entered details into "(*pdata)->pProd" the compiler stopped.
How can I allocate memory to "Product* pProd" and enter details?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char name[30];
int amount;
int price;
}Product;
typedef struct
{
int id;
Product* pProd;
int numProd;
}Cart;
void InitCashReg(Cart** pdata) {
int size,size1,j=0,i;
int PriceAllProd=0;
printf("Enter number of client --> \n");
scanf("%d", &size);
printf("Enter number of product client bought --> \n");
scanf("%d", &size1);
*pdata = (Cart*)malloc(sizeof(Cart)*size);
if (*pdata == NULL)
{
printf("cannot allocate memory\n");
return -1;
}
(*pdata)->pProd = (Product*)malloc(sizeof(Product)*size1);
if ((**pdata).pProd == NULL)
{
printf("cannot allocate memory\n");
return -1;
}
…
One of the comments says:
I need to allocate space for size1 products for each of size clients and then enter the details of products for each client.
First things first:
Separate the I/O finding sizes from the code that uses them. This is a fundamental technique in programming.
A function should do one job — yours does (at least) two: get the sizes, and allocate the space for the data given those sizes (and probably then goes on to fill in the space with more I/O operations).
That means your code should be split into at least two functions, the second of which becomes something like bool InitCashReg(size_t n_client, size_t n_prod, Cart **pdata), returning success/true or failure/false status, and taking what you called size and size1 as arguments instead of trying to read them. I'm not going to replicate the I/O code; I'll just concentrate on the memory allocation code.
enum { CLIENT_DEFAULT_ID = -1 };
bool InitCashReg(size_t n_client, size_t n_prod, Cart **pdata)
{
Cart *cart = malloc(sizeof(*cart) * n_client);
if (cart == 0)
return false;
for (size_t i = 0; i < n_client; i++)
{
cart[i]->pProd = calloc(sizeof(*cart[i]->pProd), n_prod);
if (cart[i].pProd == 0)
{
// Release already allocated space
for (size_t j = 0; j < i; j++)
free(cart[j]->pProd);
free(cart);
return false;
}
cart[i].numProd = n_prod;
cart[i].id = CLIENT_DEFAULT_ID;
}
*pdata = cart;
return true;
}
This code has not been compiled, much less tested.
I used calloc() to allocate the array of products so that the data is all zeroed; you could use malloc() instead and set the name, amount and price variables to 0 some other way. Note that this, along with the invented CLIENT_DEFAULT_ID ensures that all the allocated memory is initialized to known values.
(C++ has constructors which can be used to ensure proper initialization. C doesn't have constructors, so you have to ensure your allocated data is appropriately initialized.)

c Struct Array, Storing string and its occurrence and writing it to a file

so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.

Reallocating memory for a struct array in C

I am having trouble with a struct array. I need to read in a text file line by line, and compare the values side by side. For example "Mama" would return 2 ma , 1 am because you have ma- am- ma. I have a struct:
typedef struct{
char first, second;
int count;
} pair;
I need to create an array of structs for the entire string, and then compare those structs. We also were introduced to memory allocation so we have to do it for any size file. That is where my trouble is really coming in. How do I reallocate the memory properly for an array of structs? This is my main as of now (doesn't compile, has errors obviously having trouble with this).
int main(int argc, char *argv[]){
//allocate memory for struct
pair *p = (pair*) malloc(sizeof(pair));
//if memory allocated
if(p != NULL){
//Attempt to open io files
for(int i = 1; i<= argc; i++){
FILE * fileIn = fopen(argv[i],"r");
if(fileIn != NULL){
//Read in file to string
char lineString[137];
while(fgets(lineString,137,fileIn) != NULL){
//Need to reallocate here, sizeof returning error on following line
//having trouble seeing how much memory I need
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
int structPos = 0;
for(i = 0; i<strlen(lineString)-1; i++){
for(int j = 1; j<strlen(lineSTring);j++){
p[structPos]->first = lineString[i];
p[structPos]->last = lineString[j];
structPos++;
}
}
}
}
}
}
else{
printf("pair pointer length is null\n");
}
}
I am happy to change things around obviously if there is a better method for this. I HAVE to use the above struct, have to have an array of structs, and have to work with memory allocation. Those are the only restrictions.
Allocating memory for an array of struct is as simple as allocating for one struct:
pair *array = malloc(sizeof(pair) * count);
Then you can access each item by subscribing "array":
array[0] => first item
array[1] => second item
etc
Regarding the realloc part, instead of:
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
(which is not syntactically valid, looks like a mix of realloc function prototype and its invocation at the same time), you should use:
p=realloc(p,[new size]);
In fact, you should use a different variable to store the result of realloc, since in case of memory allocation failure, it would return NULL while still leaving the already allocated memory (and then you would have lost its position in memory). But on most Unix systems, when doing casual processing (not some heavy duty task), reaching the point where malloc/realloc returns NULL is somehow a rare case (you must have exhausted all virtual free memory). Still it's better to write:
pair*newp=realloc(p,[new size]);
if(newp != NULL) p=newp;
else { ... last resort error handling, screaming for help ... }
So if I get this right you're counting how many times pairs of characters occur? Why all the mucking about with nested loops and using that pair struct when you can just keep a frequency table in a 64KB array, which is much simpler and orders of magnitude faster.
Here's roughly what I would do (SPOILER ALERT: especially if this is homework, please don't just copy/paste):
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void count_frequencies(size_t* freq_tbl, FILE* pFile)
{
int first, second;
first = fgetc(pFile);
while( (second = fgetc(pFile)) != EOF)
{
/* Only consider printable characters */
if(isprint(first) && isprint(second))
++freq_tbl[(first << 8) | second];
/* Proceed to next character */
first = second;
}
}
int main(int argc, char*argv[])
{
size_t* freq_tbl = calloc(1 << 16, sizeof(size_t));;
FILE* pFile;
size_t i;
/* Handle some I/O errors */
if(argc < 2)
{
perror ("No file given");
return EXIT_FAILURE;
}
if(! (pFile = fopen(argv[1],"r")))
{
perror ("Error opening file");
return EXIT_FAILURE;
}
if(feof(pFile))
{
perror ("Empty file");
return EXIT_FAILURE;
}
count_frequencies(freq_tbl, pFile);
/* Print frequencies */
for(i = 0; i <= 0xffff; ++i)
if(freq_tbl[i] > 0)
printf("%c%c : %d\n", (char) (i >> 8), (char) (i & 0xff), freq_tbl[i]);
free(freq_tbl);
return EXIT_SUCCESS;
}
Sorry for the bit operations and hex notation. I just happen to like them in such a context of char tables, but they can be replaced with multiplications and additions, etc for clarity.

Resources