Why I get segfault when initializing the struct? - c

Searched around for one hour. I guess I'd better post the question here.
I simplify the code. The segfault is in the function initMyStruct.
#include "stdlib.h"
typedef struct {
int * arr1;
int * arr2;
} myStruct;
void allocMyStruct (myStruct * a, int num) {
a = malloc(sizeof(myStruct));
a->arr1 = malloc(10*sizeof(int));
a->arr2 = malloc(10*num*sizeof(int));
}
void initMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) a->arr1[i] = 0;
for (i = 0; i < 10*num; i++) a->arr2[i] = -1;
}
void freeMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) free(a->arr1);
for (i = 0; i < 10*num; i++) free(a->arr2);
free(a);
}
int main (void) {
int num = 3;
myStruct * a;
allocMyStruct (a, num);
initMyStruct (a, num);
freeMyStruct (a, num);
return 1;
}

Because you're not keeping the pointer to the newly allocated memory, instead you use an uninitialized pointer and getting undefined behavior.
You pass the a variable into allocMyStruct(), but that call is (like all others) by value, so the new value being assigned to it inside the function does not affect the value of a in main().
Change it so that allocMyStruct() either returns the new pointer value, or takes a pointer to the pointer. I would prefer the former, it's cleaner and using function return values often leads to better code:
myStruct * allocMyStruct(int num)
{
myStruct *p;
if((p = malloc(sizeof *p +
10 * sizeof *p->arr1 +
10 * num * sizeof *p->arr2)) != NULL)
{
p->arr1 = (int *) (p + 1);
p->arr2 = p->arr1 + 10;
}
return p;
}
The above code also streamlines the memory allocation, doing it all in one big malloc() call which is then "sliced" into the three parts you actually need.
If the size of arr1 is always 10 by the way, there's no point in having it dynamically allocated, it should just be int arr1[10]; in the struct declaration.

a is used uninitialized, change to:
myStruct * allocMyStruct (int num) {
myStruct *a;
a = malloc(sizeof(myStruct));
a->arr1 = malloc(10*sizeof(int));
a->arr2 = malloc(10*num*sizeof(int));
return a;
}
myStruct * a = allocMyStruct(num);
Also, there is no need to loop in your free function
void freeMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) free(a->arr1);
for (i = 0; i < 10*num; i++) free(a->arr2);
free(a);
}
Must be
void freeMyStruct (myStruct * a) {
free(a->arr1);
free(a->arr2);
free(a);
}

When you call void allocMyStruct (myStruct * a, int num) the a pointer will be passed as a value and the a parameter is a local copy of your pointer from main , after you change the local a in any of your three functions, it will not change in main.
For this you have to use double pointer as a function argument, so those functions will get an address of a pointer so they can modify it.
#include "stdlib.h"
typedef struct {
int * arr1;
int * arr2;
} myStruct;
void allocMyStruct (myStruct ** a, int num) {
*a = malloc(sizeof(myStruct));
(*a)->arr1 = malloc(10*sizeof(int));
(*a)->arr2 = malloc(10*num*sizeof(int));
}
void initMyStruct (myStruct ** a, int num) {
int i;
for (i = 0; i < 10; i++) (*a)->arr1[i] = 0;
for (i = 0; i < 10*num; i++) (*a)->arr2[i] = -1;
}
void freeMyStruct (myStruct ** a, int num) {
free((*a)->arr1);
free((*a)->arr2);
free(*a);
*a = NULL;
}
int main (void) {
int num = 3;
myStruct * a;
allocMyStruct (&a, num);
initMyStruct (&a, num);
freeMyStruct (&a, num);
return 1;
}
EDIT: Alter Mann is right about multiple freeing of the same address, on linux you would get instant crash for double freeing. And he has a simpler solution.

Related

Problem with storing value in pointer address

I managed to put the value in the pointer while in the function, However when i come back to the main i just dont get the values. Where am i wrong? sending parameters wrong? wrong allocation? Here's the code:
bool wc(int* nlines, int* nwords, int* nchars)
{
int lines=5,chars=6,words=7;
nchars = (int *) malloc(chars*sizeof(int));
*nchars = chars;
nlines = (int *) malloc(lines*sizeof(int));
*nlines = lines;
nwords = (int *) malloc(words*sizeof(int));
*nwords = words;
}
int main() {
int* chars; int* words; int* lines;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",chars,lines,words);
return 0;
}
If all you want to do is be able to set 3 int values inside a function then this is how I would so it.
#include <stdio.h>
#include <stdbool.h>
bool wc(int* nlines, int* nwords, int* nchars)
{
int lines=5,chars=6,words=7;
*nchars = chars;
*nlines = lines;
*nwords = words;
return true;
}
int main() {
int lines = 0;
int words = 0;
int chars = 0;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",chars,lines,words);
return 0;
}
If for some reason you must use pointers as shown in your example then this will do what you want.
#include <stdio.h>
#include <stdbool.h>
bool wc(int** nlines, int** nwords, int** nchars)
{
int lines=5,chars=6,words=7;
*nchars = malloc(sizeof(int));
**nchars = chars;
*nlines = malloc(sizeof(int));
**nlines = lines;
*nwords = malloc(sizeof(int));
**nwords = words;
return true;
}
int main() {
int* chars; int* words; int* lines;
int res = wc(&lines,&words,&chars);
printf("%d %d %d\n",*chars,*lines,*words);
free(chars);
free(words);
free(lines);
return 0;
}
As you can see this just means you need to add a bunch more * all over the place.
In C function input variables are passed by value, not reference. So when you assign them locally, the value in the caller scope is unaffected. E.g.
void foo(int a) {
a = 5;
}
int main() {
int b = 3;
foo(b);
// here, b is still 3
}
This is exactly what you are doing in your example, though your variables are not int, but int*.
If your input variable is a pointer though, you can change the memory that the variable points to, and this will obviously reflect in the calling scope. E.g.
void foo(int *a) {
*a = 5;
}
int main() {
int b = 3;
foo(&b);
// here, b is 5
}
In your case, you want to allocate pointers, so you want your function signature to be a pointer to a pointer. E.g.
void foo(int **a) {
*a = malloc(sizeof(int));
}
int main() {
int* b = NULL;
foo(&b);
// here, b is allocated to a valid heap area
free(b);
}

Returning a pointer to an array of structs

Let's say I have to create an array of structs that is allocated on the heap and return a pointer that points to this array of structs.
typedef struct Pair {
int x;
int y;
} Pair;
Pair** foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return &arr;
}
When I compile a program containing this function, it warns me that I am returning the address of a local variable. I assume this is because the pointer is initialised within the function (i.e. on the stack), therefore it counts as a local variable.
When I compile it, ignoring this warning, and run it anyway, the program crashes when the returned pointer is accessed.
I have tried allocating the pointer dynamically:
Pair** ptr = malloc(sizeof(**ptr));
ptr = &arr;
...
return ptr;
but the program still crashes when this pointer is accessed. How can I create this array within a function and return a pointer to this array so that it can be safely accessed?
This array is initialized on the stack but the pointer (arr) is a local variable, so the caller, main, cannot access it. You do not need to use the address of the pointer. You can access the array with the pointer itself.
Pair* foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
If you want an array of structs, the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
} Pair;
static Pair* foo(int n, int m, int length) {
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
int main(void) {
Pair *z = foo(111, 222, 3);
for (int i = 0; i < 3; ++i)
printf("z[%d]= { %d, %d }\n", i, z[i].x, z[i].y);
free(z);
return 0;
}
gives the output:
z[0]= { 111, 222 }
z[1]= { 112, 223 }
z[2]= { 113, 224 }
If you want an pointer to an array of structs, you can change your function signature from Pair** to be Pair*.
If you still want an pointer to an array of pointers, then allocate memory for a Pair struct for each index of arr.
for(int i = 0; i < length; ++i){
arr[i] = malloc(sizeof(Pair));
...
}
Instead of returning &arr, you can declare arr as
Pair** arr = malloc(sizeof(Pair*) * length);
Because arr is a local variable, it will be free when foo end. So you don't have access for arr after. To solve this you should declare array pointer in heap:
Pair** foo(int n, int m, int length)
{
Pair ** arr = (Pair**)malloc(sizeof(Pair*));
*arr = malloc(sizeof(Pair) * length);
for (int i = 0; i < length; ++i) {
(*arr)[i].x = n++;
(*arr)[i].y = m++;
}
return arr;
}

Segmentation fault using threads in C

I'm getting a seg fault within this code, but I can't find the problem anywhere. It compiles just fine with -lpthread, but it just won't run. This program takes in an integer from the command line and then creates a new thread to calculate the collatz conjecture using that value. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void print_con();
void calc_con(int *n);
int * values[1000];
int main(int argc, char * argv[])
{
int* num;
*num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, (void *)&calc_con, (void *)num);
pthread_join(thread, NULL);
print_con();
return 0;
}
void calc_con(int *n)
{
int i = 0;
int * x;
*x = *n;
*values[0] = *x;
while(*x > 1)
{
if(*x % 2 == 0)
*x /= 2;
else if(*x % 2 == 1)
{
*x *= 3;
*x++;
}
i++;
*values[i] = *x;
}
pthread_exit(0);
}
void print_con()
{
int i;
for(i = 0; i < 1000; i++)
{
if(*values[i] > 0)
printf("%d", *values[i]);
}
}
okay you need to pass a void * as an argument to pthread_create, but you still need to respect the basics:
int* num;
*num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, (void *)&calc_con, (void *)num);
Here *num = 15; you're writing 15 to an uninitialized pointer. That's undefined behaviour.
I would do:
int num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, &calc_con, &num);
note that you don't have to cast to void * from pointers on non-void. Since num is declared in the main routine, you can pass a pointer on it to your threads safely.
note that as pointed by dasblinkenlight, you also have to fix the recieving end, in calc_con, which has the same issue:
int * x; // uninitialized pointer
*x = *n; // copy data "in the woods"
just dereference into a local variable and you have your value:
int x = *((int *)n);
and another one:
int * values[1000];
is an uninitialized array of integer pointers, not an array of integers like you're intending. It should be
int values[1000];
then
values[0] = x;
(it's not because there's a lot of * operators that it's good code)
You are passing an int to your thread using a void*. This will work on many platforms, but there is no guarantees that the number would "round-trip" correctly. Once you get pointer back, you save it in a dereferenced uninitialized pointer, which is incorrect.
Pass a pointer to num instead, and copy the pointer into x directly:
void calc_con(void *n);
...
void calc_con(void *n) {
int i = 0;
int * x = n;
*values[0] = *x;
while(*x > 1) {
if(*x % 2 == 0) {
*x /= 2;
} else if(*x % 2 == 1) {
*x *= 3;
*x++;
}
i++;
*values[i] = *x;
}
pthread_exit(0);
}
...
int num = 15;
pthread_create(&thread,(pthread_attr_t*)NULL, calc_con, (void *)&num);

How to passing the pointer parameters and return them right?

Here is my code sample:
#include <stdio.h>
#include <stdlib.h>
void foo(int size, int new_size, int * ptr1, double * ptr2) {
int i;
new_size = size * 2;
ptr1 = (int *) calloc(new_size, sizeof(int));
ptr2 = (double *) calloc(new_size, sizeof(double));
for (i = 0; i < new_size; i++) {
ptr1[i] = 1;
ptr2[i] = 2;
}
}
int main(){
int i, size = 4, new_size = 4;
int *ptr1 = NULL;
double *ptr2 = NULL;
foo(size, new_size, ptr1, ptr2);
for (i = 0; i < new_size; i++) {
printf("new_size: %d\n", new_size);
printf("ptr1: %d, ptr2: %f\n", ptr1[i], ptr2[i]);
}
free(ptr1);
free(ptr2);
return 0;
}
And I have to malloc space and assign data to ptr1 and ptr2 in foo function (because I don't know the new size of them in main functin) and then use them in the main function.Why the code doesn't work? And How to implement the above process I want?
You can pass the address of the pointer to the function like so:
void foo(int size, int new_size, int ** ptr1, double ** ptr2) {
int i;
new_size = size * 2;
*ptr1 = (int *) calloc(new_size, sizeof(int));
*ptr2 = (double *) calloc(new_size, sizeof(double));
for (i = 0; i < new_size; i++) {
(*ptr1)[i] = 1;
(*ptr2)[i] = 2;
}
}
and in main
foo(size, new_size, &ptr1, &ptr2);
Your code didn't work because parameter are passed by value. ptr1 and ptr2 while being pointers are still passed by values so any modification to them(compared to modification to what they point to) will not remain after the function.
Pass the addresses of the pointers, modify the pointers in the functions and thats all, other that that I have a few observations on your code
Don't cast the return value of malloc(), it's not necessary in c, and it hurts your code readability.
Always check the return value of malloc() and pretty much any function that returns a value, because normally there is a special value indicating failure, and you don't want your program to misbehave under extraordinary conditions.
This is a version of your own code with the main issue addressed and also the observations above.
#include <stdio.h>
#include <stdlib.h>
int foo(int size, int new_size, int ** ptr1, double ** ptr2) {
int i;
new_size = size * 2;
*ptr1 = malloc(new_size * sizeof(int));
*ptr2 = NULL;
if (*ptr1 == NULL)
return 1;
*ptr2 = malloc(new_size * sizeof(double));
if (*ptr2 == NULL) {
free(*ptr1);
return 2;
}
for (i = 0; i < new_size; i++) {
(*ptr1)[i] = 1;
(*ptr2)[i] = 2;
}
return 0;
}
int main() {
int i, size = 4, new_size = 4;
int *ptr1 = NULL;
double *ptr2 = NULL;
if (foo(size, new_size, &ptr1, &ptr2) != 0)
return -1;
for (i = 0; i < new_size; i++) {
printf("new_size: %d\n", new_size);
printf("ptr1: %d, ptr2: %f\n", ptr1[i], ptr2[i]);
}
free(ptr1);
free(ptr2);
return 0;
}
In c you always pass parameters by value, it might be confusing because you are passing a pointer, but a pointer is just another variable which stores a memory address, that address is changing inside the foo() function but it's only being written into the local pointer ptr1.
Passing the address writes the value to the original pointer in main().

Double Pointer Using Error

I am having a trouble while practicing double pointer
The Error is "EXE_BAD_ACCESS" in Xcode
#include <stdio.h>
/* Program to Get Min and Max Value
in Array */
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
**maxPtr=arr[0]; // Error Line
**minPtr=arr[0]; // Error Line
for(i=1; i<5; i++)
{
if(arr[i]>**maxPtr)
**maxPtr=arr[i];
else if(arr[i]<**minPtr)
**minPtr=arr[i];
}
}
int main()
{
int arr[5]={4, 5, 7, 2, 6};
int *maxptr;
int *minptr;
SaveValue(&maxptr, &minptr, arr);
printf("%d, %d \n", *maxptr, *minptr);
}
I've thought that *dptr of **dptr = &ptr is *ptr
and **dptr means variable which *ptr pointing.
so I assume that **dptr = arr[0] means save first num of arr by reference at variable which *ptr pointing!
but I experiencing access error now.. I will thank for your help!
void SaveValue(int **maxPtr, int **minPtr, int arr[]); provides pointers to pointers to int so use them as such.
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr=arr + 0; /* same as *maxPtr = &arr[0]; */
*minPtr=arr + 0; /* same as *maxPtr = &arr[0]; */
for(i = 1; i < 5; i++)
{
if(arr[i] > **maxPtr)
*maxPtr = arr + i; /* same as *maxPtr = &arr[i]; */
else if(arr[i] < **minPtr)
*minPtr = arr + i; /* same as *minPtr = &arr[i]; */
}
}
Also this interface is a bit dangerous and unflexible; so why not pass the size of the array as well:
void SaveValue(int **maxPtr, int **minPtr, int arr[], ssize_t s)
{
*maxPtr=arr + 0;
*minPtr=arr + 0;
for(--s; s >= 0; --s)
{
if(arr[s] > **maxPtr)
{
*maxPtr = arr + s;
}
else if(arr[i] < **minPtr)
{
*minPtr = arr + s;
}
}
}
Call the fcuntion like this:
SaveValue(&maxptr, &minptr, arr, sizeof arr/sizeof *arr);
As the return value of the function is unused we could utlize it to apply some error inidication to allow the user of the function to write more stable code:
int SaveValue(int ** maxPtr, int ** minPtr, int arr[], ssize_t s)
{
int result = 0;
if ((NULL == arr) || (NULL == maxPtr) || (NULL == minPtr) || (0 > s))
{
result = -1;
errno = EINVAL;
}
else
{
*maxPtr=arr + 0;
*minPtr=arr + 0;
for(--s; s >= 0; --s)
{
if(arr[s] > **maxPtr)
{
*maxPtr = arr + s;
}
else if(arr[i] < **minPtr)
{
*minPtr = arr + s;
}
}
}
return result;
}
Use it like this:
#include <stdio.h>
int SaveValue(int ** maxPtr, int ** minPtr, int arr[], ssize_t s);
int main(void)
{
int arr[5]={4, 5, 7, 2, 6};
int *maxPtr;
int *minPtr;
int result = SaveValue(&maxPtr, &minPtr, arr, sizeof arr/sizeof *arr);
if (-1 == result)
{
perror("SaveValue() failed")
}
else
{
printf("%d, %d \n", *maxPtr, *minPtr);
}
}
The pointer should be pointing to valid memory location before dereferencing it else it will lead to undefined behavior. Below changes will fix your error.
int max;
int min;
int *maxptr = &max;
int *minptr = &min;
There is no need of double pointer here change your function prototype to
void SaveValue(int *maxPtr, int *minPtr, int arr[])
Have
int max;
int min;
in main() and call this API accordingly
SaveValue(&max,&min,arr);
I'll assume your code is purely for pointer learning purposes and not an attempt to implement this operation in a practical situation. So if you want to have maxptr and minptr in main() pointing to the maximum and minimum values in arr[], I think you should change your double pointer assignments from **maxPtr=arr[0] to *maxPtr=&arr[0], so your code would become:
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr = &arr[0]; // Error Line
*minPtr = &arr[0]; // Error Line
for (i = 1; i < 5; i++) {
if (arr[i] > **maxPtr)
*maxPtr = &arr[i];
else if (arr[i] < **minPtr)
*minPtr = &arr[i];
}
}
In this case, when you make the assignments, you don't want to dereference the double pointers. Instead, you should assign it with the address of the element you want to show when you dereference them in main().
You don't need to use the double asterisk when initialize the maxPtr and minPtr pointers in the function SaveValue, neither in the for loop body. MaxPtr and minPtr both are double pointers, but is still the memory direction of maxptr in main(). So you only need to dereference them with a single asterisk, to acces the memory direction them points to.
The source correct source code is this:
#include <stdio.h>
/* Correct program to Get Min and Max Value in Array */
void SaveValue(int **maxPtr, int **minPtr, int arr[])
{
int i;
*maxPtr=arr[0];
*minPtr=arr[0];
for(i=1; i<5; i++)
{
if(arr[i]>*maxPtr)
*maxPtr=arr[i];
else if(arr[i]<*minPtr)
*minPtr=arr[i];
}
}
int main(void)
{
int arr[5]={4, 5, 7, 2, 6};
int *maxptr;
int *minptr;
SaveValue(&maxptr, &minptr, arr);
printf("%d, %d \n", maxptr, minptr);
return 0;
}
When I compile it with GCC and execute it, i get the next output:
7, 2.
Remember that depending of the environment (Operating System, version, compiler, standards) that you use the program results may vary.

Resources