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.
Related
I've managed to point towards an array, however, the closest I've gotten to pointing to a char* list only prints out the individual letters as shown below:
#include <stdio.h>
main()
{
char* list[2];
list[0] = "Hullo";
list[1] = "GoodBye";
char* pointer = &(list);
char* back = *(list);
printf("%c", back[8]);
}
0 through 4 of back prints out "Hullo", 5 through 7 is whitespace, and 8 through 14 prints out "Goodbye".
I'm wondering how I can avoid printing this list character to character, as it becomes a very inconvenient issue when returning lists of unspecified sizes and planning on using them for another function etc.
It feels like you're looking for:
#include <stdio.h>
int
main(void)
{
char * list[2];
list[0] = "Hullo";
list[1] = "GoodBye";
char ** pointer = list;
for( size_t i = 0; i < sizeof list / sizeof *list; i++ ){
printf("%s\n", *pointer++);
}
}
but maybe you're looking for something like:
#include <stdio.h>
#include <stdlib.h>
char **
foo(void)
{
char **p = malloc(3 * sizeof *p);
if( p == NULL ){
perror("malloc");
exit(1);
}
p[0] = "Hullo";
p[1] = "GoodBye";
p[2] = NULL;
return p;
}
int
main(void)
{
char **p = foo();
for( ; *p; p++ ){
printf("%s\n", *p);
}
free(p);
}
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.
There is some code piece right here below:
main ()
{
char in[8];
char out[255];
iconv_t cd;
cd = iconv_open("gb18030", "utf-8");
...
char *p_in = in;
char *p_out = out;
size_t inlen = strlen(in);
size_t outlen = sizeof(out);
if (iconv(cd, &p_in, &inlen, &p_out, &outlen) < 0)
{
...
return -1
}
...
return 0;
}
I can't totally understand the 2nd and 3rd parameters of the call to iconv. Why should that be ** pointer not the * pointer as the input? Can anyone explain the cases in C when the ** pointer should be used?
Pointer to pointer is used where the passed pointer is need to be modified in the called function and that modification need to be seen in the caller function. This is required because in C arguments are passed by value. So, when an argument is passed to a function then it simply copied to the function's parameter and created a local copy having block scope. Any change to that variable will not be seen in the argument that has been passed.
void foo(in x){
x = 10;
}
int main(void){
int x = 5;
foo(x)
printf("%d\n", x); // x will be 5
}
Same happens with pointers
void bar(char *p){
p = "foobar";
}
int main(void){
char *p = NULL;
bar(p);
if(p)
printf("p is pointing to %s\n", p);
else
printf("p is NULL\n"); // This will
}
Using a pointer to pointer will do the desired job (pointing p to the string "foobar"
void bar(char **p){
*p = "foobar";
}
int main(void){
char *p = NULL;
bar(&p);
if(p)
printf("p is pointing to %s\n", p);
else
printf("p is NULL\n"); // This will
}
Another use is when an array of string is need to passed to a function. Like
int main(int argc, char **argv)
or
void print_fruits(char **fruits, size_t len){
for(int i = 0; i < len; i++)
printf("%s\n", fruits[i]);
}
int main(void){
char *fruits[5] = {"Apple", "Banana", "Cherry", "Kiwi", "Orange"};
print_fruits(fruits, sizeof(fruits)/sizeof(fruits[0]));
}
Note that in function call print_fruits, fruits in the argument list will decay to pointer to its first element and the expression fruits will become of type char ** after the conversion.
In this C program I read in words typed with my keyboard to a char pointer. The pointer is stored in an pointer array. Then I want to sort the array with qsort by the function comparison. I give it the pointer to my pointer array.
It doesnt sort the array at all. I dont know if I got here a UB, or I miss memory by wrong allocation.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
bool read_word(char ***a, int *length);
int comparison(const void *p, const void *q);
int main()
{
int *length = malloc(sizeof(int));
*length = 0;
char **array = malloc(sizeof(char *));
bool go = false;
while(go == false)
{
printf("Enter word: ");
go = read_word(&array,length);
}
qsort(array, *length - 1,sizeof(char *), comparison);
printf("\n");
for(int i = 0; i < *length; i++)
printf("%s\n", array[i]);
return 0;
}
bool read_word(char ***a, int *length)
{
char ch;
++*length;
char *word = malloc(20 * sizeof(char) + 1);
char *keep_word;
char **temp = realloc(*a,*length * sizeof(*a));
if(!temp)
exit(EXIT_FAILURE);
*a = temp;
keep_word = word;
while((ch = getchar()) != '\n')
*keep_word++ = ch;
*keep_word = '\0';
if(word == keep_word)
{
free(word);
--*length;
return true;
}
(*a)[*length - 1] = word;
printf("%s", (*a)[*length -1]);
printf("\nh\n");
return false;
}
int comparison(const void *p, const void *q)
{
const char *p1 = p;
const char *q1 = q;
return strcmp(p1,q1);
}
change to
int length = 0;//no need malloc
char **array = NULL;//first value is NULL
qsort(array, length, sizeof(char *), comparison);//not length-1
int ch;//type of return value of getchar is int
for(int i = 0; i < 20 && (ch = getchar()) != '\n'; ++i)//i : guard
const char *p1 = *(const char **)p;//qsort pass pointer to object to comparison function
const char *q1 = *(const char **)q;//if char *, char **
You do
keep_word = word;
and later
if(word == keep_word)
The condition in brackets is always true.
On a side note, your program is error-prone and hard to understand because you use pointers way too much. In main(), length should be int, not int*, array should be char*, not char** . In the read_word, a should be char**, not char***. Don't use pointers unless necessary!
The function f allocates its result always to the same address, that makes the main() function always print out the same result, how do I make the function allocate the variable an another address and free them.
int *f(int a) {
int b = 2 * a;
return &b;
}
int main(void) {
int *p4, *p8;
p4 = f(4);
p8 = f(8);
printf("p4: %i / p8: %i\n", *p4, *p8);
}
The function f does not allocate anything, it returns the address of a local variable with automatic storage. Accessing data via this pointer invokes undefined behavior as soon as b goes out of scope, when f returns. The compiler should be able to detect such a silly bug.
To allocate memory, you should use malloc:
#include <stdio.h>
#include <stdlib.h>
int *f(int a) {
int *p = malloc(sizeof(*p));
if (p != NULL)
*p = 2 * a;
return p;
}
int main(void) {
int *p4 = f(4);
int *p8 = f(8);
if (p4 != NULL && p8 != NULL) {
printf("p4: %i / p8: %i\n", *p4, *p8);
}
free(p4);
free(p8);
return 0;
}
You have to declare b as static ore better yet,declare b as parameter in f function. You could do something like this
static bool f(int a,int *b)
{
if(NULL == b)
{
return false;
}
*b = a * 2;
return true;
}
It is better to write functions that return nothing(void) or a boolean to let you know if everything went fine and use pointers to modify data and reduce the use of the stack. Most safety-critical standards adopt this rule.