Consider the following abstracted code that reads some bytes from a file:
typedef struct A{
int size;
char * dataArray;
}A
A load(char* filename, int inSize)
{
A newA;
newA.size = inSize;
FILE *filePtr;
filePtr = fopen(filename,"rb");
char buff[1];
int i = 0;
newA.dataArray = ( char*)malloc(sizeof(char) * newA.size);
for (i = 0; i < newA.size; i++)
{
fread(buff, sizeof(char), 1, filePtr);
newA.dataArray[i] = buff[0];
}
char* copyOfDataArray = (char*)malloc(sizeof(char) * newA.size);
for (i = 0; i < newA.size; i++)
{
fread(buff, sizeof(char), 1, filePtr);
copyOfDataArray[i] = newA.dataArray[i];
}
newA.dataArray = copyOfDataArray;
return newA
}
void Initialize()
{
A first = load("file1", 100);
A second = load("file2", 20);
}
Both calls to function load return the expected result (data array has the same bytes as the file). Variables first and second are never used again.
However after a couple of hundreds lines of code the program always crashes with:
*malloc.c:2451: sYSMALLOC: Assertion '(old_top == (..... failed.*
The crash always occurs on the same line of code, but that line has nothing to do with variables first, second or even with struct A whatsoever.
My question is: is my way of instancing and loading 'first' and 'second' wrong? Can it cause some kind of memory leak / memory overflow that crashes the program long after the load function has finished?
Bonus: The crash does not occur if I only load "file1", as soon as i load both "file1" and "file2" the crash reappears.
Sorry for the long question.
You have memory leaks there. You have to free the previously allocated memory in newA.dataArray, before you assign there a new memory.
As stated by Joachim, read operation is very time consuming and you shall read data in blocks to minimize overhead.
Additionally, you have to close file descriptors, otherwise they will be depleted soon.
There are many issue on the code as already given by others.
Please checks bellow
typedef struct A{
int size;
char * dataArray;
}A
A load(char* filename, int inSize)
{
A newA;
newA.size = inSize;
FILE *filePtr = NULL ; //Use NULL
char buff[1]; //Size of buffer is only 1 ,If needed increase that to copy more at a time
int i = 0;
filePtr = fopen(filename,"rb");
//Try to check for the filePtr == NULL or not
newA.dataArray = ( char*)malloc(sizeof(char) * newA.size);
//Same checking should be done here
for (i = 0; i < size; i++) //What is size
{
fread(buff, sizeof(char), 1, filePtr);
newA.dataArray[i] = char[0]; //What is char[0]
}
//instead this you can read the bytes in a single call, use that.
// fread(buff, sizeof(char), <size to read >, filePtr);
char* copyOfDataArray = (char*)malloc(sizeof(char) * newA.size);
for (i = 0; i < size; i++)
{
fread(buff, sizeof(char), 1, filePtr);
copyOfDataArray[i] = newA.dataArray[i];
}
//why reading again once you done above.
newA.dataArray = copyOfDataArray;
return newA; //Please check: How you can return a auto variable.
}
void Initialize()
{
A first = load("file1", 100);
A second = load("file2", 20);
}
Related
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.
So I need to write a function that reads all the elements inside a bit file. The point is that I don't know how many elements there could be inside, but I know what type of elements are. So I tried to write this function:
void loadData(Parallelogram **array) {
FILE *data; long size;
//int numberOfElements = 0;
int numberOfObjects = 0;
if ((data = fopen(name, "rb"))!=NULL) {
fseek(data, 0, SEEK_END);
size = ftell(data);
fseek(data, 0, SEEK_SET);
if (size<(long)sizeof(Parallelogram)) {
printf("The file is empty try to open another file maybe");
} else {
Parallelogram *tempArray;
numberOfObjects = size/sizeof(Parallelogram);
tempArray = realloc(*array, numberOfObjects*sizeof(Parallelogram));
if (tempArray==NULL) {
printf("There was an error reallocating memory");
} else { *array = tempArray; }
fread(*array, sizeof(Parallelogram), numberOfObjects, data);
}
}
fclose(data);
}
The elements are struct objects of type Parallelogram, storing a few floats.
The commented out part was me trying another method form another question but not understanding the real mechanism. Anyways when I call the function the array is empty. What am I getting wrong?
EDIT: As requested this is the main function where I call the function loadData()
int main() {
Parallelogram *paraArray = NULL;
loadData(¶Array);
}
EDIT: complete function more or less like the OP's.
You may do something like:
void loadData(Parallelogram **array, size_t * n) {
FILE *data;
if ((data = fopen("file.bin", "rb"))!=NULL) {
Parallelogram buffer[100]; // may be malloc'd
size_t chunk_size = 100;
size_t read_size = 0;
size_t number_of_objects = 0;
Parallelogram *aux = NULL;
*array = NULL;
while ((read_size = fread(buffer, sizeof *buffer, chunk_size, data)) > 0) {
aux = realloc(*array, (number_of_objects + read_size) * sizeof *buffer);
if (aux == NULL) {
// ERROR
free(*array);
// clean, break/exit
}
*array = aux;
memcpy(*array + number_of_objects, buffer, read_size*sizeof *buffer);
number_of_objects += read_size;
}
// check file for errors (ferror()) before exit
fclose(data);
*n = number_of_objects;
}
}
I'm trying to make a file system in C. I have trouble with this portion of my code when I'm printing my values in the code below:
for (int i = 0; i<NUM_POINTERS; i++) {
printf("before SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
write_blocks(0, 1, SB);
for (int i = 0; i<NUM_POINTERS; i++) {
printf("after SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
my write_blocks method:
int write_blocks(int start_address, int nblocks, void *buffer)
{
int i, e, s;
e = 0;
s = 0;
void* blockWrite = (void*) malloc(BLOCK_SIZE);
/*Checks that the data requested is within the range of addresses of the disk*/
if (start_address + nblocks > MAX_BLOCK)
{
printf("out of bound error\n");
return -1;
}
/*Goto where the data is to be written on the disk*/
fseek(fp, start_address * BLOCK_SIZE, SEEK_SET);
/*For every block requested*/
for (i = 0; i < nblocks; ++i)
{
/*Pause until the latency duration is elapsed*/
usleep(L);
memcpy(blockWrite, buffer+(i*BLOCK_SIZE), BLOCK_SIZE);
fwrite(blockWrite, BLOCK_SIZE, 1, fp);
fflush(fp);
s++;
}
free(blockWrite);
/*If no failure return the number of blocks written, else return the negative number of failures*/
if (e == 0)
return s;
else
return e;
}
And here's what gets printed:
before SB->root[0]=1
before SB->root[1]=2
before SB->root[2]=3
before SB->root[3]=4
before SB->root[4]=5
before SB->root[5]=6
before SB->root[6]=7
before SB->root[7]=8
before SB->root[8]=9
before SB->root[9]=10
before SB->root[10]=11
before SB->root[11]=12
before SB->root[12]=13
before SB->root[13]=14
after SB->root[0]=1234344888
after SB->root[1]=32688
after SB->root[2]=3
after SB->root[3]=4
after SB->root[4]=5
after SB->root[5]=6
after SB->root[6]=7
after SB->root[7]=8
after SB->root[8]=9
after SB->root[9]=10
after SB->root[10]=11
after SB->root[11]=12
after SB->root[12]=13
after SB->root[13]=14
I don't understand why my first and second pointer value change?
Some additional information: SB is a superBlock here's my structures:
typedef struct iNode
{
int id;
int size;
int pointers[NUM_POINTERS];
} iNode;
typedef struct superBlock
{
int magic_number;
int block_size;
int num_blocks;
int num_inodes;
iNode *root;
iNode jNodes[20];
} superBlock;
Is this single threaded?
Does the modified SB->root[0,1] contain the data you are trying to write?
What is your BLOCK_SIZE?
I suspect the problem is outside of write_blocks(). My best guess would be that you accidentally freed SB somewhere and malloc gave you the same address. After the malloc check (print or debugger) both buffer and blockWrite and make sure they are different and valid.
Unrelated Issues:
printf has more % than params
You should check the return of malloc
e is never set
s and i are equal. AKA redundant.
Out of bounds error causes a memory leak (since it is after the malloc)
usleep is strange perhaps you want fsync?
I am trying to save struct data to file. I saved the data this way.
node_trx * trx_list;
trx_list = calloc(1, sizeof(node_trx *));
trx_list->amount = "123123123";
trx_list->currency = 123;
trx_list->next_node = NULL;
if (1 != fwrite(trx_list, length, 1, f)) {
//error
}
free(trx_list);
Here is my struct:
typedef struct {
char amount;
int currency;
struct node_trx * next_node; } node_trx;
Main problem is after i saved struct to file and then after read, when print values, it is printing wrong values. For example: i stored currency as 123, then printed 6788576 this kind of numbers.
here is my reading code:
int read_last_trx_from_file (const char * file_name, node_trx * * trx, unsigned * trx_len)
{
FILE * f;
*trx = NULL;
if (NULL == (f = fopen(tools_get_full_filename_const(file_name), "rb")))
{
return 2; //error
}
size_t fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fprintf(stdout, "file size: %zd\n", fsize);
if (!fsize)
{
fclose(f);
return 3; //no data
} else {
if (fsize == 1) {
return 3; // no data
}
}
rewind(f);
if (NULL != (*trx = (node_trx *) calloc(1, fsize)))
{
if (1 != fread(*trx, fsize, 1, f))
{
fclose(f);
free(*trx);
return 2; //error
}
}
fclose(f);
*trx_len = fsize;
return 0; //OK }
Main function that calls read function:
int display_trx() {
node_trx * card_data;
if (3 != read_last_trx_from_file(LAST_TRX_OBJECT, &card_data, &data_set_len)) {
if (card_data != NULL) {
printf("%s AMOUNT \n", card_data->amount);
printf("%d CURRENCY \n", &card_data->currency);
}
}
}
After i read this way , when i print amount data, segmentation fault error occurs. so why segment error occured?
And when i print currency, it printing 734364636 this kinda numbers. So why it prints wrong numbers.
Or i only wrote pointer of struct to file?
Please help me guys.
There are two obvious errors in your code.
In struct declaration, the type of amount is char, but when you initialize it in trx_list->amount = "123123123";, you assigned a string, or char[10] array (there is an extra one for NULL terminator).
In function display_trx, second printf, the result of &card_data->currency is int *, not int. If you want to print out currency, why don't follow the first print, use card_data->currency (without &)? You get that large number because you are printing pointer value implicitly converted into int, or the address of currency in card_data.
And there is one error which compiler will not warn you (because it is not syntactically wrong.). As BLUEPIXY said in the comments, when allocating and initializing trx_list, you should really use calloc(1, sizeof(node_trx)). You are allocating space for what pointer trx_list points to, not the pointer itself, so there should not be an asterisk in sizeof.
My suggestion is using a "smart" compiler, such as gcc, and enable warnings. This is a good practice (at least for me). Thank you!
I'm having an infuriating issue here where I'm crashing on malloc/calloc/strdup and I'm assuming currently that it's because of a buffer over run somewhere.
I'm finding this very difficult to find and I was wondering if any of you can offer me a hand. I'll post code snippets here, and link to full source.
File reading and array operations: (common.c)
Pastebin
char * S6_ReadFileBytes(const char* path)
FILE * file;
long length;
char * bytes = NULL;
file = fopen(path, "r");
fseek(file, 0, SEEK_END)
length = ftell(file);
fseek(file, 0, 0);
bytes = (char*)calloc(1, (size_t)length + 1);
fread(bytes, 1, (size_t)length, file);
return bytes;
S6_Array * S6_ArrayNew(size_t count, size_t typeSize)
S6_Array * a = (S6_Array*)malloc(sizeof(S6_Array));
a->typeSize = typeSize;
a->Length = count;
void * S6_ArrayGet(S6_Array * a, int idx)
return &((char*)a->Data)[idx * a->typeSize];
void S6_ArraySet(S6_Array * a, int idx, void * val)
memcpy(&((char*)a->Data)[idx * a->typeSize], val, a->typeSize);
void S6_ArrayGrow(S6_Array * a, int amount)
void * data;
data = realloc(a->Data, (a->Length + amount) * a->typeSize);
a->Data = data;
a->Length += amount;
void S6_ArrayPushBack(S6_Array * a, void* val)
S6_ArrayGrow(a, 1);
S6_ArraySet(a, a->Length - 1, val);
CSV Reading: (CSV.c)
Pastebin
void S6_CSV_PushRect(S6_Array ** rectangles, S6_Rectangle * rect)
if( !*rectangles )
*rectangles = S6_ArrayNew(1, sizeof(S6_Rectangle*));
S6_ArraySet(*rectangles, 0, &rect);
else
S6_ArrayPushBack(*rectangles, &rect);
int S6_CSV_ReadRects(const char* file, S6_Array ** rectangles)
char * bytes = S6_ReadFileBytes(file);
char * line;
char * nameIndex;
size_t nameLength;
S6_Rectangle * tempRect;
line = strtok( bytes , "\n");
while( line )
nameIndex = strstr(line, ",");
tempRect = (S6_Rectangle*)calloc(1, sizeof(S6_Rectangle));
nameLength = (size_t)(nameIndex - line) + 1;
strncpy(tempRect->name, line, nameLength-1);
tempRect->name[nameLength-1] = '\0';
sscanf(nameIndex, "%*[,]%d%*[,]%d%*[,]%d%*[,]%d", &tempRect->x, &tempRect->y, &tempRect->w, &tempRect->h)
S6_CSV_PushRect(rectangles , tempRect);
strtok(NULL, "\n");
free(bytes);
A function where I modify the array: (BinPacker.c)
Pastebin
int S6_BinPacker_Pack(S6_Array * rectangles, int binSize)
// This sort appears to be working fine. View pastebin for test.
qsort(rectangles->Data, rectangles->Length, sizeof(S6_Rectangle*), S6_BinPacker_CompareRects);
CSV Writing [CRASH]
: (CSV.c)
Pastebin
void S6_CSV_WriteRects(const char* file, S6_Array * rectangles)
char * bytes = NULL;
char buffer[128];
S6_Rectangle * tempRect;
size_t i;
for( i = 0; i < rectangles->Length; ++i)
tempRect = *(S6_Rectangle**)S6_ArrayGet(rectangles, i);
memset(buffer, '\0', sizeof(buffer));
sprintf(buffer,
"%s,%d,%d,%d,%d\n",
tempRect->name,
temprect->x,
temprect->y,
temprect->w,
temprect->h);
if( bytes )
bytes = strcat(bytes, _strdup(buffer));
else
bytes = _strdup(buffer);
So I'm crashing here on the strcat(bytes, _strdup(buffer)) line. When I separate it out It's still the string duplication or any sort of allocation I've tried.
I get the following break dialog from visual studio:
Windows has triggered a breakpoint in myapp.exe.
This may be due to a corruption of the heap, which indicates a bug in Slant6.Debug.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Slant6.Debug.exe has focus.
The output window may have more diagnostic information.
And the break point it triggers is in tidtable.c on
PFLS_GETVALUE_FUNCTION flsGetValue = FLS_GETVALUE;
SOLUTION
strdup doesn't do any allocations, and even if it did I would be leaking like crazy. So instead of:
bytes = strcat(bytes, _strdup(buffer));
in CSV.c, I replaced it with some manual string concatenation that's easier for me to read (and remember).
size_t oldSize = strlen(bytes);
size_t bufferSize = strlen(buffer);
size_t newSize = oldSize + bufferSize ;
char * newMem = (char*)calloc(newSize + 1, 1);
memcpy(newMem, bytes, newSize);
memcpy(&newMem[oldSize], buffer, bufferSize);
free(bytes);
bytes = newMem;
/SOLUTION
I'm thinking that this line:
bytes = strcat(bytes, _strdup(buffer));
Does not do what you think it does.
You are making a copy of a string (buffer), and then concatenating that onto bytes. The duplicated string is never freed and
bytes is only as big as the last _strdup, thus doing a strcat will overflow the buffer.
You need to allocate (or reallocate) strlen(bytes) + strlen(buffer), etc. etc. for the strcat.