Dynamic Array Allocation, pass by value, out of range - c

I have two questions about dynamic allocated array. I have looked up some similar questions but still didn't find the answer.
Pass by value
Basically, I write two functions, one for allocation and another for free memory. When I pass the array pointer by value, the allocation function didn't work (as expected) but the free function works. And in my naive understanding, even if we pass the array pointer by value, the allocation should still work since it allocates a memory at the same memory address the value represented. And if we refers to that address later, regardless of the variable name, we should be able to find that space. This is the code:
void main()
{
int * array;
allocation(array);
deallocation(array);
}
void allocation(int * result)
{
result = malloc(8293 * sizeof(result));
}
void deallocation(int * result)
{
free(result);
}
For deallocation test, I declared int * array = malloc(23123* sizeof(int)) in the main function instead of using allocation function. Again, the deallocation works.
Out of range access.
void main()
{
FILE * fp = fopen("sometext.txt");
int * A = malloc(100 * sizeof(int));
int * B = malloc(200 * sizeof(int));
/* Now I accidentally access A from 0-199 and B from 0-999 using a for loop*/
char buffer[500];
int i,x;
for (i=0; i<200; i++)
{
fgets(fp,buffer);
sccanf(buffer, "%d", x);
A[i]=x;
}
for (i=0; i<1000; i++)
{
fgets(fp,buffer);
sccanf(buffer, "%d", x);
B[i]=x;
}
}
Both for loop should not work. However, I somehow get passed the first loop and only get seg fault in the second loop. And the error I get is traced back to sccanf (I tested the code without assign any value to A or B, and it works. So the sccanf statement should be fine.) The gdb error message is : isoc99_sscanf (s=, format=).
The full bt message is below, SOL[] is my B[] here and the actual sscanf read more variables. I can post full code if you are interested.
#0 0x00007ffff7a6869b in _IO_vfscanf_internal (s=s#entry=0x7fffffffd3b0,
format=format#entry=0x4010f8 "%*d%5c%5c%5d %lf %lf %lf %*f %*f %*f\n",
argptr=argptr#entry=0x7fffffffd4d8, errp=errp#entry=0x0) at vfscanf.c:343
#1 0x00007ffff7a72a0c in __GI___isoc99_vsscanf (
string=0x7fffffffd650 " 4545SOL HW123234 2.687 0.089 7.120 -1.1448 0.0920 0.6016\n", format=0x4010f8 "%*d%5c%5c%5d %lf %lf %lf %*f %*f %*f\n",
args=args#entry=0x7fffffffd4d8) at isoc99_vsscanf.c:43
#2 0x00007ffff7a72997 in __isoc99_sscanf (s=<optimized out>,
format=<optimized out>) at isoc99_sscanf.c:31
#3 0x0000000000400a9c in read (PMI=0x603490, COION=0x606ce0,
COUNTERION=0x60dd70, SOL=0x7ffff7f58010, in=0x603010, out=0x603250)
at thick_calc.c:97
#4 0x0000000000400915 in main () at thick_calc.c:52
Thanks!

You are not reassiging the pointer, it should be
void main()
{
int * array;
allocation(&array);
if (array != NULL)
deallocation(array);
}
void allocation(int **result)
{
if (result == NULL)
return;
*result = malloc(8293 * sizeof(int));
}
void deallocation(int * result)
{
free(result);
}
by passing the pointer, you can modify it's content, but you cannot change where it points to, so you must pass a pointer to the pointer, i.e. the address to the pointer so you can modify where it points to.
The problem in your code is that your pointer remains invalid in the scope of main, so when you pass it to free it's not actually pointing to the malloced memory block.
Doing that is causes undefined behavior. Reading or writing past the malloced block causes undefined behavior, so you cannot expect a given behavior, because it's undefined.
It means, it could cause a Segmentation Fault, or it could work, or anything could happen because it's undefined.
Eventualy you will write to a special location in memory and something will happen, you can't be sure what is happening meanwhile since again it's undefined behavior.

Related

malloc() fails to allocate memory inside a function in C

I want to allocate memory dynamically inside a function. The function is named func_1 and is declared as follows:
int func_1(int **destination);
Here destination is a pointer to a pointer. This pointer contains the address of the pointer to which I want to allocate memory dynamically inside the function.
The function func_1 has the following code:
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
*destination[i] = i; //segmentation fault comes HERE
}
}
Below is my main() function:
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
When I try to run this program, I get a segmentation fault (SIGSEGV) error. I used GDB to locate the source of this fault, and it turned out that the line inside the for loop is the culprit for this error.
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
I want to know:
Why am I getting this error ?
How can this be fixed ?
Thanks for help !
[] (array subscripting) operator has precedence 2
* (dereference) operator has precedence 3
In your code *destination[i] means the same as *(destination[i]). This value is uninitialized and it leads to segmentation fault.
If you will use explicit priority of operation (*destination)[i] you will get the expected result.
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i; //no segmentation fault
}
}
you can read more about precedence here
Full code:
#include <stdio.h>
#include <stdlib.h>
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i;
}
}
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
Why am I getting this error ?
You are overwriting the destination pointer instead of assigning the value returned by malloc to the pointer pointed to by the destination pointer.
Instead of *destination = (int*)malloc(sizeof(int) * 10) you should type **destination = malloc(sizeof(int) * 10).
Instead of *destination[i] = i you should type (**destination)[i] = i.
In C, the array subscript operator [] has a higher precedence than the indirection operator *. In addition to that, the former is left-to-right associative, while the latter is right-to-left associative.
In your case this means that you need to type (**destination)[i] = i; instead of **destination[i] = i, because otherwise the [i] will be evaluated before the ** and you end up indirecting a wild pointer (which will cause a segmentation fault extremely likely in the general and absolutely certainly in this case, since you are referencing a null pointer when i == 0).
How can this be fixed ?
The "just make it work" fix is the one I presented above.
However, that does not address the fundamental issue with your code, which is that it is unnecessarily complicated. Using a pointer to a pointer is very error-prone and should be avoided. Indeed, there is no need to use one at all in this case.
The following does exactly what you want without all the unnecessary complexity:
int* func_1()
{
int* destination = malloc(sizeof(int) * 10);
for (int i = 0; i < 10; ++i)
{
destination[i] = i;
}
return destination;
}
int main()
{
int* pointer = func_1();
free(pointer);
return 0;
}
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
As I demonstrated above, there is no reason to pass a pointer to the pointer to the function. Memory allocated with malloc is yours to use forever , you just need to keep track of it and release it with a call to free when you no longer need it. How you keep track of the memory doesn't matter - simply returning a pointer is enough in this case. Modifying pointer inside func_1 rather than catching the function's return value provides no additional benefit and only serves to make the code more complicated than it needs to be.
I get the impression that you are somewhat confused about pointers, so I recommend that you revise the subject. Here is a quite clear explanation regarding pointers that also covers pointers to pointeres (and pointers to pointers to pointers): How do pointers work in C?
Read more:
Operator Precedence and Associativity in C
What is a segmentation fault?

Segmentation fault after realloc in function

I have created this code to test one error, that I get in my main code, and it shares the same problem. I'm always getting either segmentation fault or corrupted data (zeros or strange numbers).
Here is the code:
int *p=NULL;
int func (int **point);
int main() {
int num = 5647;
p = malloc(sizeof(int)*2);
p[0] = num;
p[1]= 657;
printf("%d\n", p[0]);
printf("%d\n", p[1]);
func(&p);
printf("%d\n", p[0]);
printf("%d\n", p[1]);
printf("%d\n", p[2]);
printf("%d\n", p[3]);
return 0;
}
int func (int **point){
*point = realloc(*point,sizeof(int)*4);
if (*point==NULL){
printf("\n abort \n");
exit(0);
}
*point[0] = 867;
*point[1]= 777;
*point[2] = 67;
*point[3]= 77;
}
I'm getting the segmentation fault on the *point[1]=777;. If I'm trying to do like point[1]=777; I'm getting wrong data. With any changes in int func (int **point); or func(&p); I'm getting segmentation fault on realloc.
Please advise, I have read information about double pointers and tried to follow all solutions I found, but every time I'm getting this error.
Your problem is operator precedence, change *point[0] to (*point)[0] and so forth.
What you have right now is *(point[0]). You treat a pointer to a single element as a pointer to multiple consecutive elements and then dereference some indeterminate value as an address. This results in undefined behavior, which luckily for you manifests as a crash.
After the change you first dereference point and then use that address to index into consecutive elements you allocated.
Two suggestions for improvement:
Don't assign the result of realloc directly to *point. If the call fails, then you leak the original memory. Assign it to a temporary first for verification.
Also, try not to repeat types. Instead of sizeof(int) try for sizeof(**point), i.e whatever the output buffer is supposed to point at. That way you won't have silent errors in your code if you change the type from int to something else.
void *point_check = realloc(*point,sizeof(**point)*4);
if (point_check == NULL){
printf("\n abort \n");
exit(0); // If this ever returns instead of exit, `*point` will not leak
}
*point = point_check;

Program gives segmentation fault while trying to malloc for a pointer member of structure

I wrote my code which works well on netbeans, but gives me a seg fault on putty. I tried to use the gdb, but it seems helpless in which gives me
Program received signal SIGSEGV, Segmentation fault.
0x00000000004006c1 in init_vector ()
(gdb) back trace
#0 0x00000000004006c1 in init_vector ()
#1 0x0000000000400664 in main ()
Here is my code, hope someone can help me out
typedef struct v_
{
int* data;
int size;
int capacity;
}vector;
int main()
{
// vector of floats
vector *vec;
init_vector(vec);
insert_element_vector(vec, 5);
int ele = access_element_vector(vec, 0);
printf("%d\n", ele);
return 0;
}
void init_vector( vector* v)
{
v->data = malloc(sizeof(int) * INIT_VECTOR_SIZE);
v->size = 0;
v->capacity = INIT_VECTOR_SIZE;
}
void insert_element_vector( vector* v, int element_to_insert)
{
if(v->capacity == v->size)
{
v->data = realloc(v->data, sizeof(int) * v->capacity * 2);
v->capacity *= 2;
}
v->data[v->size] = element_to_insert;
v->size += 1;
}
In your code, in init_vector() function, you're directy accessing the passed pointer like
v->data
and more. In case the passed pointer is NULL or invalid, this will invoke undefined behavior.
In your case, vec being an uninitialized automatic local variable, the content is indeterminate. So, the pointer points to invalid memory, essentially. Trying to access it invokes the UB.
To avoid
Always better to initialize the automatic local variables (here, pointer to NULL) and put a (NULL) check for the incoming pointer.
Pass a memory address to init_vector which is valid.
For the second step, you can pass the address of a scalar variable, like
vector *v;
init_vector(&v);
to get things working.
Another possibility is, use malloc() or similar allocator function to allocate memory to vec in main() before passing that to init_vecor().
In main, you declare a *vec;, and then start using it, but it is never associated with any memory. A segmentation fault is exactly what I would expect.
Declare it as vector vec;, and then pass its address to the calls (&vec), and the problem is resolved.

C: Passing one dimension of a 2D array results in segfault

it has been a while since I wrote my last lines of C and I'm having issues getting into the hang of C at this moment. I guess this is probably a stupid mistake I'm making, but after having researched the issue for some time I still couldn't figure it out what I'm doing wrong. So this is how my code looks like:
int read_signal_from_file(const char* path, float* signal, SF_INFO * info) {
SNDFILE *sndFile;
sndFile = sf_open(path, SFM_READ, info);
signal = malloc(info->frames * sizeof(float));
long numFrames = sf_readf_float(sndFile, signal, info->frames);
...
}
and
int main(int argc, char *argv[]) {
float** signals = malloc(NUM_FILES * sizeof(float*));
float avg = 0.0;
SF_INFO tmp_info;
for(int i = 0; i < NUM_FILES; i++) {
read_signal_from_file(INPUT_FILES[i], signals[i], &tmp_info);
for(long j = 0; j < tmp_info.frames; j++) {
printf("Sample no #%ld: %f\n", j, signals[i][j]);
}
}
}
inside of read_signal_from_file(), I have no troubles accessing the allocated memory portion. But as soon as I'm trying to access it from the scope of the main function (e.g. as in the printf() example above, I get corrupted results that look suspiciously like uninitialized memory or overflows. If I try to operate on that data, (e.g. by calling vDSP_meanv(), the application crashes with a segfault.
Firstly, you don't have a 2D array, you have a pointer-to-pointer.
Then, the pointers themselves don't point to anything, they are uninitialized because you don't allocate memory for them - thus your program invokes undefined behavior.
So, either allocate memory for them using malloc() in a for loop, or even better, use a real array:
float (*arr)[COLUMN_SIZE] = malloc(sizeof(*arr) * ROW_SIZE);
You are allocating the array of pointers, but you aren't setting them to anything:
float** signals = malloc(NUM_FILES * sizeof(float*));
Which means that you are passing an uninitialized pointer (signals[i]) here:
read_signal_from_file(INPUT_FILES[i], signals[i], &tmp_info)
Because signals[i] is passed by value, it isn't going to be changed in the function call, so it is still going to be uninitialized after read_signal_from_file returns.
A simple change would be to pass by reference:
int read_signal_from_file(const char* path, float* &signal, SF_INFO * info) { ... }
(As mentioned) You are allocating the signals array of pointers, but you don't assign the pointers in this array. When you allocate signal in read_signal_from_file you do reserve the memory but you're assigning the pointer to the local signal variable. If you want to assign the allocated signal to the signals array in your main function you should pass a pointer to the pointer:
read_signal_from_file(INPUT_FILES[i], &signals[i], &tmp_info);
and change your read_signal_from_file function to accept it:
int read_signal_from_file(const char* path, float ** signal, SF_INFO * info) {
// ...
*signal = malloc(info->frames * sizeof(float));
// ...
You pass float *signal to read_signal_from_file() and reassign signal there but that just changes the local var signal, not signals[i] in main().
Change the signature of read_signal_from_file() to
int read_signal_from_file(const char* path, float** signal, SF_INFO * info)
change your malloc() to
*signal = malloc(info->frames * sizeof(float));
and pass signals+i instead of signals[i]

2D arrays passed through functions in c

I'm having a problem with my program. I need my program to read from a text file, the first consists of the dimensions of the 2d array the rest is the contents of the array. I have coded the readWord function which reads from textfiles and it works but when i do anything on the main function with the array it crashes. Please could you help.
int main()
{
int num_it, cols, rows;
char** myworld;
num_it = readWorld(myworld,&cols, &rows);
myworld[1][2]='x';/*it crashes when i make this statement*/
}
int readWorld(char** world, int* width,int* height)
{
int result=0,i,cols=0,rows=0;
char buff[25];
FILE* file = fopen ("world.txt", "r");
fscanf(file, "%d %d %d\n", width, height, &result);
/*Dynamic allocation*/
world = (char**)malloc(*(height)* sizeof(char*));
for(i=0;i<*height;i++)
{
world[i] = (char*)malloc(*width*sizeof(char));
}
/*store data in array*/
while(fgets(buff, sizeof buff, file) != NULL)
{
if (strlen(buff) >1){
for(cols=0; cols<=(strlen(buff)); ++cols)
{
world[rows][cols] = buff[cols];
}
++rows;
}
}
fclose(file);
return result;
}
You need to allocate the memory for myworld in the actual caller!
What's happening here is that you are passing the pointer by value to the function.
The pointer value is changed by the function but that's not going to adjust the one in the caller.
Two options: use a triple indirection (ie pass a pointer to the the pointer) or allocate in the main sub. I prefer the latter, mainly because you can control the memory deallocation in a more symmetrical manner; even if you fixed this problem your code still has the memory leak.
What you're experiencing is undefined behaviour as you are attempting to access memory your program does not own.
Your myworld variable in main is never initialized and points to junk, so when you try to access it bad things happen. Think about why: you are passing a copy of the variable to readWorld. You correctly allocate memory inside there, and make the copy point to it, but the original pointer (in main) still points to whatever random location it pointed to before.
If you want the memory for it to be allocated inside the readWorld function and made accessible via the myworld variable in main then you must pass a pointer to myworld to readWorld; in other words, you must pass a triple pointer.
Try this:
int readWorld(char*** world, int* width,int* height)
{
char **tempworld = malloc(...);
// do whatever
*world = tempworld;
return result;
}
int main()
{
char **myworld = NULL;
readWorld(&myworld, ...);
return 0;
}

Resources