I have a dynamic 2d array inside this struct:
struct mystruct{
int mySize;
int **networkRep;
};
In my code block I use it as follows:
struct myStruct astruct[100];
astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);
// do stuff...
int i;
for(i=0; i<100; i++)
freeMatrix(astruct[i].networkRep, 200);
This is how I declare the 2d array:
int** declareMatrix(int **mymatrix, int rows, int columns)
{
mymatrix = (int**) malloc(rows*sizeof(int*));
if (mymatrix==NULL)
printf("Error allocating memory!\n");
int i,j;
for (i = 0; i < rows; i++)
mymatrix[i] = (int*) malloc(columns*sizeof(int));
for(i=0; i<rows; i++){
for(j=0; j<columns; j++){
mymatrix[i][j] = 0;
}
}
return mymatrix;
}
And this is how I free the 2d array:
void freeMatrix(int **matrix, int rows)
{
int i;
for (i = 0; i < rows; i++){
free(matrix[i]);
}
free(matrix);
matrix = NULL;
}
The strange behvior that I'm seeing is that when I compile and run my program everything looks OK. But when I pipe the stdout to a txt file, I'm getting a seg fault. However, the seg fault doesn't occur if I comment out the loop containing the "freeMatrix" call. What am I doing wrong?
I don't see any problem in free code, except, freeMatrix get called for 100 times whereas your allocation is just 1.
So, either you allocate as below:
for(int i=0; i<100; i++) //Notice looping over 100 elements.
astruct[i].networkRep = declareMatrix(astruct[i].networkRep, 200, 200);
Or, free for only 0th element which you have allocated in your original code.
freeMatrix(astruct[0].networkRep, 200);
On sidenote: Initialize your astruct array.
mystruct astruct[100] = {};
struct myStruct astruct[100];
astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);
// do stuff...
int i;
for(i=0; i<100; i++)
freeMatrix(astruct[i].networkRep, 200);
You allocated one astruct but free 100 of them; that will crash if any of the 99 extra ones isn't NULL, which probably happens when you do your redirection. (Since astruct is on the stack, it will contain whatever was left there.)
Other issues:
You're using numeric literals rather than manifest constants ... define NUMROWS and NUMCOLS and use them consistently.
Get rid of the first parameter to declareMatrix ... you pass a value but never use it.
In freeMatrix,
matrix = NULL;
does nothing. With optimization turned on, the compiler won't even generate any code.
if (mymatrix==NULL)
printf("Error allocating memory!\n");
You should exit(1) upon error, otherwise your program will crash and you may not even see the error message because a) stdout is buffered and b) you're redirecting it to a file. Which is also a reason to write error messages to stderr, not stdout.
astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);
your not passing the address of the pointer. It just passes the value in the memory to the function which is unncessary.
And your only initializing first variable of struct but while you are trying to free the memory you are unallocating memory which is not yet allocated (astruct[1] and so on till 100 ).
When you use a malloc , it actually allocates a bit more memory than you you specified. extra memory is used to store information such as the size of block, and a link to the next free/used block and sometimes some guard data that helps the system to detect if you write past the end of your allocated block.
If you pass in a different address, it will access memory that contains garbage, and hence its behaviour is undefined (but most frequently will result in a crash)
To index and count an unsigned integer type is enough. size_tis the type of choice for this as it is guaranteed to be larger enough to address/index every byte of memory/array's element on the target machine.
struct mystruct
{
size_t mySize;
int ** networkRep;
};
Always properly initialise variables:
struct myStruct astruct[100] = {0};
Several issues with the allocator:
Give it a chance to returned specific error codes. This typically is done by setting using the function returned value to to so.
Use size_t for counters and indicies and sizes ("rows", "columns")(for why please see above).
Do proper error checking.
Clean up in case an error occurs during work.
do not cast the value returned by malloc(), as in C it's not necessary, not recommended
Use perror() to log error, as it gets the most from the OS about the as possibe.
A possible to do this:
int declareMatrix(int *** pmymatrix, size_t rows, size_t columns)
{
int result = 0; /* Be optimistc. */
assert(NULL != pmatrix);
*pmymatrix = malloc(rows * sizeof(**pmymatrix));
if (NULL == *pmymatrix)
{
perror("malloc() failed");
result = -1;
goto lblExit;
}
{
size_t i, j;
for (i = 0; i < rows; i++)
{
(*pmymatrix)[i] = malloc(columns * sizeof(***pmymatrix));
if (NULL == (*pmymatrix)[i])
{
perror("malloc() failed");
freeMatrix(pmymatrix); /* Clean up. */
result = -1;
goto lblExit;
}
for(i = 0; i < rows; ++i)
{
for(j = 0; j < columns; ++j)
{
(*pmymatrix)[i][j] = 0;
}
}
}
}
lblExit:
return 0;
}
Two issues for the de-allocator:
Mark it's work as done be properly de-initilaising the pointer.
Perform validation of input prior to acting on it.
A possible to do this:
void freeMatrix(int *** pmatrix, size_t rows)
{
if (NULL != pmatrix)
{
if (NULL != *pmatrix)
{
size_t i;
for (i = 0; i < rows; ++i)
{
free((*pmatrix)[i]);
}
}
free(*pmatrix);
*pmatrix = NULL;
}
}
Then use the stuff like this:
struct myStruct astruct[100] = {0};
...
int result = declareMatrix(&astruct[0].networkRep, 200, 200);
if (0 != result)
{
fprintf("declareMatrix() failed.\n");
}
else
{
// Note: Arriving here has only the 1st element of astruct initialised! */
// do stuff...
}
{
size_t i;
for(i = 0; i < 100; ++i)
{
freeMatrix(&astruct[i].networkRep, 200);
}
}
Related
I would like some help accessing the arrays in my struct. My program compiles without any errors, but stalls when I try to change some values in my struct. I'm stumped as to what the problem is, and would greatly appreciate some assistance.
Global struct declaration:
typedef struct Data {
float timestamp[array_length];
float azimuth[array_length];
float distance[array_length];
float signal_strength[array_length];
} Datain;
Datain *dataptr;
This is were I try to initialize the arrays to what I would like them to be:
for (i = 0; i < array_length; i++)
{
dataptr->timestamp[i]=-100;
dataptr->distance[i]=-100;
dataptr->azimuth[i]=-100;
dataptr->signal_strength[i]=-100;
}
Let me know what you think
dataptr is an uninitialized pointer, it's pointing to nowhere. You have to
allocate memory for it:
dataptr = malloc(sizeof *dataptr); // or malloc(size * sizeof *dataptr)
// for allocating size Datain objects
if(dataptr == NULL)
{
// error handling
// do not continue
}
for(i=0;i<array_length;i++)
{
dataptr->timestamp[i]=-100;
dataptr->distance[i]=-100;
dataptr->azimuth[i]=-100;
dataptr->signal_strength[i]=-100;
}
/*
or if you do the malloc(size * sizeof *dataptr)
for(size_t i = 0; i < size; ++i)
{
for(size_t j = 0; j < array_length; ++j)
{
dataptr[i].timestamp[j]=-100;
dataptr[i].distance[j]=-100;
dataptr[i].azimuth[j]=-100;
dataptr[i].signal_strength[j]=-100;
}
}
*/
and later you don't have to forget to free the memory with
free(dataptr);
And if dataptr is meant to be a single object, then you don't need to declare
it as a pointer:
Datain dataptr; // no * here
then later in a function
for(i=0;i<array_length;i++)
{
dataptr.timestamp[i]=-100;
dataptr.distance[i]=-100;
dataptr.azimuth[i]=-100;
dataptr.signal_strength[i]=-100;
}
and here you don't need to free the memory.
The following code works fine without the statement d = *dummy; which is a double pointer dereference. However if this line is present, a segmentation fault occurs. Why so?
The code allocates and initializes memory for data structs dynamically. I was trying to simplify access to the returned pointer-to-pointer.
#include <stdlib.h>
#include <stdio.h>
typedef struct s_dummy {
char dummy_number;
} Dummy;
int mock_read_from_external_source() {
return 4;
}
int load_dummies(Dummy** dummies, int* num_of_dummies) {
*num_of_dummies = mock_read_from_external_source();
*dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));
if (!dummies) {
return 1; // allocation unsuccessful
}
// Iterate dummies and assign their values...
for (int i = 0; i < *num_of_dummies; i++) {
(*dummies + i)->dummy_number = i;
}
return 0;
}
void main() {
Dummy** dummies;
Dummy* d;
int num_of_dummies = 0;
int *p_num_of_dummies = &num_of_dummies;
int err;
err = load_dummies(dummies, p_num_of_dummies);
// Segmentation fault occurs when dummies is dereferenced
d = *dummies;
if (err) {
exit(err);
}
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
}
}
Thanks in advance.
You are getting the fault because of UB, in part caused by trying to use variable objects without memory. dummies, although created as a Dummies **, has never been provided memory. At the very least, your compiler should have warned you about dummies not being initialized in this call:
err = load_dummies(dummies, p_num_of_dummies);
This is easily addressed by simply initializing the variable when it is created:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
Then come the run-time errors. The first is called a fatal run-time on my system, which means the OS refused to continue because of a serious problem, in this case an attempt to dereference a null pointer in this line:
dummies = (Dummy) calloc(*num_of_dummies, sizeof(Dummy));
Because you created a Dummy ** called dummies, the first step is to create memory for the pointer to pointers dummies, then create memory for the several instances of dummies[i] that will result. Only then can the members of any of them be written to.
Here is one method illustrating how memory can be created for a Dummies pointer to pointers, ( d ) and several Dummies instances ( d[i] ):
Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
{
int i;
Dummy **d = {0};
d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
if(!d) return NULL;
for(i=0;i<numPointers;i++)
{ //Now create Dummies *
d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
if(!d[i]) return NULL;
}
return d;
}
In your main function, which by the way should really be prototyped at a minimum as: int main(void){...}, this version of loadDummies could be called like this:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
After using this collection of dummies, be sure to free all of them in the reverse order they were created. Free all instances of dummies[0]-dummies[numPointers-1] first, then free the pointer to pointers, dummies
void freeDummies(Dummy **d, int numPointers)
{
int i;
for(i=0;i<numPointers;i++)
{
if(d[i]) free(d[i]);
}
if(d) free(d);
}
Called like this:
freeDummies(dummies, 4);
dummies was never assigned a value, so de-referencing will attempt to reach some random memory which is almost certainly not going to be part of your program's allocated memory. You should have assigned it to &d.
But you don't even need to do that. Just use &d once when you call the function.
Also, if you return the number of dummies allocated instead of 1/0, you can simplify your code. Something like the below (not tested):
#include <stdio.h>
int mock_read_from_external_source() {
return 10;
}
typedef struct Dummy {
int dummy_number;
} Dummy;
int load_dummies(Dummy** dummies) {
int want, i = 0;
if((want = mock_read_from_external_source()) > 0) {
*dummies = (Dummy*) calloc(want, sizeof(Dummy));
if(*dummies) {
// Iterate dummies and assign their values...
for (i = 0; i < want; i++) {
(*dummies)[i].dummy_number = i;
}
}
}
return i;
}
int main() {
Dummy* d = NULL;
int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d
if(num_of_dummies > 0) {
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}
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?
UPDATE:
I've changed the static array for a dynamic, but I still get the segment violation error, although eclipse says:
*** glibc detected *** (path to file) double free or corruption (!prev): 0x00000000004093d0 ***
StructHashTable is a typedef...
int main() {
...
StructHashTable *B0 = (StructHashTable *) malloc(N_ELEMS*sizeof(StructHashTable));
...
}
void resizeHash(StructHashTable *hash) {
int size = currentElements + N_ELEMS;
StructHashTable newHash[size];
int i;
for (i = 0; i < size; i++) newHash[i].key = FREE;
for (i = 0; i < currentElements; i++) insertHash(newHash, hash[i]);
currentElements = size;
hash = (StructHashTable *) realloc(hash, size*sizeof(StructHashTable));
if (hash != NULL) {
for (i = 0; i < size; i++) hash[i] = newHash[i];
}
}
What's wrong now? Am I using in a bad way realloc? or what? C is driving me crazy...
OLD:
I'm working in university homework and I need to resize an static array in C, it has to be static, the debbugger says segment violation...
I have a main function that declares the array...
// File: main.c
int main() {
...
StructHashTable hash[N_ELEMS];
...
}
At some point on runtime I need more elements than N_ELEMS and I've written a function to do it in HashTable.c, that's the method:
// File: HashTable.c
#define N_ELEMS 32
int currentElements = N_ELEMS
void resizeHashTable(StructHashTable *hash) {
int size = currentElements + N_ELEMS;
StructHashTable newHash[size];
int i;
// Inicialize newHash
for (i = 0; i < size; i++) newHash[i].key = FREE;
// Insert old hash elements to the new table...
for (i = 0; i < currentElements; i++) {
insertHash(newHash, hash[i]);
}
currentElements = size;
// I've tried making hash null with no luck...
//hash = NULL;
//free(hash);
// HERE'S THE ERROR...
hash = newHash;
// I've tried *hash = *newHash with the same result...
}
Can someone tell me how to do what I'm trying to do?
Thanks.
You are getting error because you are trying to modify the l-value for a statically allocated array 'hash'.
Whenever you define an array (as in main)
StructHashTable hash[N_ELEMS];
sizeof(StructHashTable)*N_ELEMS bytes of memory is allocated for hash, and hash points to the first byte. Such an allocation is called static allocation and you cannot make hash point to some other memory allocation. It will give error as you specified, because the l-value i.e left hand side value cannot be modified. Neither you can free the memory assigned to hash. Memory assigned to hash will be freed only when main will terminate.
// HERE'S THE ERROR...
hash = newHash;
I suggest you to use dynamic memory allocation for hash in main, if you wish to resize hash during run time.
int main() {
...
//Initial hash table creation
StructHashTable *B0 = (StructHashTable *) malloc(N_ELEMS*sizeof(StructHashTable));
...
...
//Do something
...
...
//hash table full. So resize hash table. This function call need not be inside main. Just for illustration purpose I am doing it here.
B0 = resizeHash(B0);
...
}
And here's your modified resizeHash function.
StructHashTable* resizeHash(StructHashTable *oldHash) {
int size = currentElements + N_ELEMS;
int i;
//Allocate memory for newHash with larger number of elements.
StructHashTable *newHash = (StructHashTable*) malloc(size * sizeof(StructHashTable));
if (newHash != NULL) {
for (i = 0; i < currentElements; i++) {
// Copy one by one oldHash table elements into newhash table
//Something like below, or whatever you have been doing before to copy.
newHash[i] = oldHash[i];
}
}
//Free memory occupied by oldHash
free(oldHash);
//Set new value for currentElements
currentElements = size;
//return the newHash address to calling function.
return (newHash);
}
The following code is not working correctly. I'm getting a segfault when I run the program. I ran my program through gdb and found out that the error is occuring in the fillArrays(int**,int) function.
GDB is displaying the following parameters for fillArrays(int**,int):
fillArrays (arrays=0x0,numArrays=3)
Here is the source code to my program
#include <stdlib.h> /* malloc and free */
#define MULTIPLIER 1
#define SMALL 10
#define BIG 20
void allocateSmallArrays(int **arrays,int numArrays) {
int index,freeIndex;
int outerIndex,innerIndex;
arrays = malloc(numArrays*sizeof(int*));
if(arrays == NULL) {
printf("out of memory\n");
exit(1);
}
for(index = 0;index < numArrays;index++) {
arrays[index] = malloc(SMALL*sizeof(int));
if(arrays[index] == NULL) {
printf("out of memory\n");
exit(1);
}
}
}
void fillArrays(int **arrays,int numArrays) {
int outerIndex,innerIndex;
for(outerIndex = 0;outerIndex < numArrays;outerIndex++) {
for(innerIndex = 0;innerIndex < SMALL;innerIndex++)
arrays[outerIndex][innerIndex] = 0;
}
}
void deallocateSmallArrays(int **arrays,int numArrays) {
int index;
for(index = 0;index < numArrays;index++)
free(arrays[index]);
free(arrays);
}
int main(void) {
int numArrays = (3 * MULTIPLIER);
int **arrays = 0;
allocateSmallArrays(arrays,numArrays);
fillArrays(arrays,numArrays);
deallocateSmallArrays(arrays,numArrays);
arrays = 0;
return 0;
}
I was under the assumption that since arrays was allocated in allocateSmallArrays, that passing it through fillArrays would 0 out the allocated arrays and then deallocate in the last function. How do I go about accomplishing this?
The problem is that allocateSmallArrays changes its own copy of the arrays pointer. So the result of the malloc is lost and after the function is done, in the caller arrays is still 0. You could:
Pass a triple pointer int ***arrays and do to *arrays everything you're doing to arrays
Return the pointer instead of void
A C FAQ deals with this very subject.