I have function that deallocates struct:
typedef struct matrix_t {
int r; // num of rows
int c; // num of cols
int *values;
} matrix_t;
function that does that is:
void deallocate_matrix(matrix_t **ptr) {
if (ptr != NULL && *ptr != NULL) {
free((*ptr)->values);
(*ptr)->values = NULL;
free(*ptr);
*ptr = NULL;
}
}
Then my main:
int main(int argc, char *argv[]) {
matrix_t *M[4] = {NULL};
char op[2] = {0};
int op_ret[2] = {0};
M[0] = matrix_input();
scanf(" %c", &op[0]);
M[1] = matrix_input();
M[2] = calc(M[0], M[1],op[0]);
matrix_print(M[2]);
deallocate_matrix((matrix_t **)&M[1]);
assert(M[1] == NULL); //this looks ok, M[1] is NULL
return 0;
}
But if I omit deallocate_matrix((matrix_t **)&M[1]); and deallocate with function calc like this:
matrix_t *calc(matrix_t *A, matrix_t *B, char op) {
matrix_t *M = NULL;
//some code to compute M
deallocate_matrix((matrix_t **)&A);
deallocate_matrix((matrix_t **)&B);
return M;
}
the assertion M[1]==NULL would fail, so I am clearly doing something wrong in the calc function, but I am not sure what.
Your code is correct. The assert is wrong. Get rid of it and you won't have an issue. You have freed the matrix.
What's happening is that calc takes A and B by value. So it can't change the value of A or B in the caller. So they won't be NULL after the call.
M[2] = calc(M[0], M[1],op[0]);
Here, we pass the values of M[0] and M[1] to calc. So calc can't change the value of M[0] or M[1] because it doesn't get a pointer to them. That's fine. There no reason it should.
Please just get out of the habit of senselessly setting pointers to NULL when you deallocate what they point to. It causes lots of pain the more complex your code gets.
You see the way free works, right? Your functions should work the same way for sanity, so:
void deallocate_matrix(matrix_t *ptr) {
if (ptr != NULL) {
free(ptr->values);
free(ptr);
}
}
Simple and easy to use.
Related
I am trying to compile and run in my desk an answers in one of the problems of leetcode, this 1 only for practice and learning proposes, but when i trying to run in a specific line of code there are the issue, with double pointers.
int **vale=(int**)malloc(n*sizeof(int*));
//*vale=(int*)malloc(m*sizeof(int*));
vale = spiralMatrix(m, n, Lista, ptr, vale);}
the problem is when the code reach the line of *returnColumnSizes the code crash.
i know that a double pointer is like a matrix, and for use then we nned to allocate the memory, so is for that i am allocating the double pointer first. So now i can send it to the function but it doesn't work. what is that i doing wrong?
int** spiralMatrix(int m, int n, struct ListNode* head, int* returnSize, int** returnColumnSizes){
*returnSize = m;
*returnColumnSizes = (int*)malloc(m*sizeof(int)); ---> this crash
int **res = (int**)malloc(m*sizeof(int*));
thanks!
To avoid the XY Problem, I won't try to answer your LeetCode question. Instead, we will discuss your topic's central question, "How can I Correctly Pass this double pointer to a function in C".
Double pointer means simply an address that point to another pointer. For example, let's say we have a simple pointer, char* foo = "Hello", if we pass foo to a function, we are giving the address of "Hello", But what if we want to pass foo itself, here the concept of the double-pointer becomes handy, char** bar = &foo, now, if we pass bar, we are passing the address of foo and not "Hello" this time.
Full Example:
#include <stdio.h>
void change_by_pointer(char* s) {
s = "One";
}
void change_by_double_pointer(char** s) {
*s = "Double";
}
int main() {
char* foo = "Hello";
printf("foo = %s\n", foo);
// Change by pointer
change_by_pointer(foo);
printf("foo = %s\n", foo);
// Change by double pointer
char** bar = &foo;
change_by_double_pointer(bar); // Or change_by_double_pointer(&foo);
printf("foo = %s\n", foo);
return 0;
}
Output:
foo = Hello
foo = Hello
foo = Double
Finally, I'm not sure what you are trying to do with spiralMatrix() but based on the params datatypes, this is how you deal with it.
#include <stdio.h>
// Please ignore the behavior of this function.
// This is just an example of how you deal with double-pointers.
int** spiralMatrix(int m, int n, struct ListNode* head, int* returnSize, int** returnColumnSizes){
*returnSize = m;
*returnColumnSizes = malloc(m * sizeof(int));
**returnColumnSizes = 3;
int **res = returnColumnSizes;
return res;
}
int main() {
int returnSize = 1;
int* returnColumnSizes = NULL;
printf("returnSize = %d\n", returnSize);
printf("Calling spiralMatrix()...\n");
int** Res = spiralMatrix(2, 0, NULL, &returnSize, &returnColumnSizes);
printf("returnSize = %d\n", returnSize);
printf("returnColumnSizes = %d\n", *returnColumnSizes);
printf("Res = %d\n", **Res);
return 0;
}
Output:
returnSize = 1
Calling spiralMatrix()...
returnSize = 2
returnColumnSizes = 3
Res = 3
I was reading a page of "Understanding and Using C Pointers" when this function appeared:
void safeFree(void **pp) {
if (pp != NULL && *pp!= NULL) {
free(*pp);
*pp = NULL;
}
}
and an example code from it:
int main(int argc, char **argv) {
int* pi = (int*)malloc(sizeof(int));
*pi = 5;
safeFree((void**)&pi);
return EXIT_SUCCESS;
}
My point is, checking pp != NULL in the if condition in this scenario is useless, right? Because according to the way this code is written this condition will never be false. But there is a scenario in which this condition will be true, assuming **pp expects a memory address and (assumed by me) a memory address of a variable can never be NULL? Or did the writer did that checkup in case someone did something like this?
int main(int argc, char **argv) {
int **pi = NULL;
safeFree((void**)pi);
return EXIT_SUCCESS;
}
Thanks.
Having said that safeFree is just confusing and does not provide safety. Because the code assumes that the API user will always pass a particularly constructed pointer. Consider these:
tricky 0 (screws up a)
#include <stdio.h>
#include <stdlib.h>
void safeFree(void **pp) {
if (pp != NULL && *pp!= NULL) {
free(*pp);
*pp = NULL;
}
}
int main() {
int *a;
int **p;
a = malloc(5 * sizeof(int));
p = malloc(1 * sizeof(a));
a[0] = 10;
p[0] = a;
fprintf(stderr, "%d\n", a[0]);
safeFree((void **)p); /* grrrr */
fprintf(stderr, "%d\n", a[0]);
}
tricky 1 (crashes)
int main() {
int a[] = { };
int b[] = { 1 };
int c[] = { 2 };
int **p = malloc(3 * sizeof(int *));
p[0] = a, p[1] = b, p[2] = c;
safeFree((void **)p); /* grrrr */
}
The function checks for NULL mainly for cases like your second. If an actual variable address is passed that check will not fail but never trust your caller to be sane.
Why does this program result in a segmentation fault? I'm trying to have an array of pointers that is dynamically allocated memory so that I can have an array of strings.
I've searched for similar issues like How to pass a double pointer to a function without segmentation fault C language
Please explain why it it seg-faulting
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void mem_alloc(char* p, char** dp);
int entries = 0;
int mem_allocated = 0;
int main() {
char* p = "ksdfahj93qhf9";
char* p1 = "siodfnrieopq";
char* p2 = "erf9ih94gri9g";
char** dp = NULL;
mem_alloc(p, dp);
mem_alloc(p1, dp);
mem_alloc(p2, dp);
for(int i = 0; i < entries; i++) {
printf("%s", dp[i]);
}
}
void mem_alloc(char *p, char** dp) {
if(entries == mem_allocated)
if(mem_allocated == 0)
mem_allocated = 3;
void** temp = realloc(dp, mem_allocated * (sizeof(p)));
if(!temp)
perror("Memory allocation failed!");
dp = (char**) temp;
strcpy(dp[entries++], p);
}
In your mem_alloc function you modify the function parameter dp. This modification is not visible outside of the function. As a result, the dp in main never changes and is still set to NULL.
You need to pass the address of this variable to the function, then in the function you dereference that pointer to change it.
So you function becomes:
void mem_alloc(char *p, char ***dp) {
if(entries == mem_allocated)
if(mem_allocated == 0)
mem_allocated = 3;
char **temp = realloc(*dp, mem_allocated * (sizeof(p)));
if(!temp)
perror("Memory allocation failed!");
*dp = temp;
(*dp)[entries++] = strdup(p); // space also needs to be allocated for the new string
}
And you call it like this:
mem_alloc(p, &dp);
Two errors. First is the one mentioned by dbush.
Second, you are not allocating space for your string before you copy it. You can use strndup() instead of strcpy().
typedef struct
{
int member;
} mystruct;
void myfunc(mystruct **data)
{
mystruct *const *p;
for(p = data; *p !=NULL; p++)
{
printf("hello\n");
}
}
void main(int argc, char *argv[])
{
myfunc(NULL);
}
tried with the above code am getting segmentation fault, its mainly something wrong in that for loop, how to just remove this segmentation fault in that for loop.... actually am learning this double pointer stuff, so i may be a little stupid in asking few question.... thanks in advance
The *p in the for loop dereferences the first pointer.
But that pointer is NULL, as you call your function with myfunc(NULL);.
Whenever you dereference a nullpointer, you invoke undefined behaviour (e.g. a segmentation fault).
typedef struct
{
int member;
} mystruct;
void myfunc(mystruct **data)
{
mystruct *const *p;
// this loop assumes data to be a valid pointer
// to a NULL-terminated array!
for(p = data; *p != NULL; p++)
{
printf("hello\n");
}
}
int main()
{
mystruct s;
mystruct *arr[2];
arr[0] = &s; // arr[0] points to s
arr[1] = NULL; // null-terminator
s.member = 13;
myfunc(arr);
// myfunc(NULL); // undefined behaviour
return 0;
}
you can fix this by checking data in myfunc:
void myfunc(mystruct **data)
{
mystruct *const *p;
// first check data
if(data != NULL)
{
// loop still assumes data to be a NULL-terminated array!
for(p = data; *p != NULL; ++p)
{
printf("hello\n");
}
}
}
...
myfunc(NULL); // well defined as the pointer will be checked
if you just want to iterate over a range, consider the standard approach:
void myfunc_range(mystruct *begin, mystruct *end)
{
mystruct const *it;
for(it = begin; it != end; ++it)
{
printf("hello %d\n", it->member);
}
}
int main()
{
mystruct s;
mystruct arr[2];
s.member = 42;
myfunc_range(&s, &s + 1); // iterate over a single element
arr[0].member = 13;
arr[1].member = 37;
myfunc_range(arr, arr + sizeof(arr) / sizeof(*arr)); // iterate over the whole array
myfunc_range(arr + i, arr + i + k); // iterate over elements arr[i..i+k-1]
myfunc_range(NULL, NULL); // well defined as NULL == NULL (an empty range)
// myfunc(arr, &s); // undefined behaviour as s is not part of the array arr
return 0;
}
Thanks for all your answers, exactly now while accessing the NULL value in the condition part of the for loop is leading to the segmentation fault.
The code confused me.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void create_int(int *p)
{
p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
You are not passing the pointer value back from the function. Try:
void create_int(int **p) {
*p = (int *) malloc(sizeof(int));
}
int main() {
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
The variable p in the function create_int is a copy of the variable p in main. So any changes made to p in the called function does not get reflected in main.
To make the change get reflected in main you need to either:
Return the changed value:
int* create_int(int *p) {
p = malloc(sizeof(int));
// err checking
return p:
}
...
// in main:
p = create_int(p);
Or pass the address of p as:
void create_int(int **p) {
*p = malloc(sizeof(int));
// err checking
}
...
// in main:
create_int(&p);
You need a pointer to a pointer like this:
void create_int(int **p)
{
*p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
As folks have pointed out, it's failing since you're not actually changing the pointer that the caller has.
A different way to think about the code might be to notice that it's basically wrapping malloc(), i.e. it's doing a memory allocation but with intelligence added. In that case, why not make it have the same prototype (=call signature) as malloc()? That makes it clearer in the caller's context what's going on, and easier to use:
int * create_int(void)
{
return malloc(sizeof (int));
}
int main(void)
{
int *p = create_int();
assert(p != NULL);
return 0;
}
Also, in C you should never cast the return value of malloc() (see Do I cast the result of malloc?).
You need to send a pointer to a pointer to be able to assign a memory to it via a function
void create_int(int **p)
{
*p = (int*)malloc(sizeof_int));
}
int main()
{
int* p = NULL;
create_int(&p);
assert(p != NULL);
return 0;
}
Your code contains two pointers: one in the create_int function and another one in main. When you call create_int, a copy of the pointer in main is made and used, then eliminated when the create_int function returns.
So, any changes you did to the copy within create_int remain there and are not propagated back to main.
The only way to propagate changes between functions in C (aside from, obviously, returning new values) is to pass a pointer to the changed values. This way, while the pointer being passed will be copied, the value that it points to will be the same, so changes will apply.
Since you're trying to change a pointer, you need a pointer-to-pointer.
void create_int(int **pp)
{
// this changes the pointer that `p` points to.
*pp = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
// this sends a pointer to the pointer p in main
create_int(&p);
assert(p != NULL);
return 0;
}