Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto check if a char* points to a string literal in C

Tags:

I have a struct

struct request {   int code;   char *message; }; 

that I'd like to free properly.

I have the following function to do that:

void free_request(struct request *req) {   if (req->message != NULL) {       free(req->message);   }   free(req);   req = NULL; } 

The problem is that I get an "free(): invalid pointer"/segfault error from the compiler when I try to free a request that has been created using a string literal:

struct request *req; req = malloc(sizeof(struct request)); req->message = "TEST"; free_request(req); 

Since I want to create request structs in different places, once using literals (on the client side) and once using *chars that I read from a socket (on the server side) I was wondering if there is a function to make sure that I don't try to free the literals while still allowing me to free the message I have created using a malloc.

like image 426
Niklas Avatar asked Aug 03 '10 16:08

Niklas


People also ask

Is char * a pointer or a string?

The 'char *' doesn't magically create a string, it really is just a pointer (to a single character).

How do you recognize a string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

Is a string literal a pointer?

String literals are passed to functions as pointers to a stored string. For example, given the statement: printf( "Please enter a positive value for the angle: " );

Can you index a string literal in C?

Of course it is, a string literal is of array type. It is converted to a pointer to char in the expression and is like an any pointer to char . char *p = "abc"; char c = p[1];


2 Answers

There is no standard function that lets you know if a pointer was dynamically allocated or not. You should include a flag in your struct to inform yourself of it, or only use dynamically allocated strings (strdup is your friend in this case). Depending on your networking setup, it might be simpler to use strdup (well, to tell the truth, it is simpler to use the strdup at all).

With strdup:

struct message* req; req = malloc(sizeof *req); req->message = strdup("TEST"); free_request(req); 

With a flag:

struct message {     int code;     char* message;     bool isStatic; // replace to 'char' if bool doesn't exist };  void free_request(struct message* req) {     if (!req->isStatic) free(req->message);     free(req); }  struct message* req; req = malloc(sizeof *req); req->message = "TEST"; req->isStatic = 1; free_request(req); 

Also, don't forget to zero your allocated memory when you create an object. That could save you a lot of trouble.

req = malloc(sizeof *req); memset(req, 0, sizeof *req); 

That, and setting req to NULL from free_request won't have any effect. You either need to take a struct message** or do it yourself after the function calls.

like image 152
zneak Avatar answered Sep 27 '22 16:09

zneak


There is no way to tell if you are using a string literal (Well, you can put string literals in a custom .section created by GCC, and then examine the string pointer to determine if it is contained in the .section of literals). However...there is a better way using a simple programming pattern.

Allocation With Literal

Normal case. A call to free(req) will work as expected: freeing the request structure.

struct *req;  req = malloc(sizeof(*req)); req->message = "TEST"; 

Allocation With Dynamic String

In the following, some_string is a string you wish to store as the request message. It can be either a literal, or a dynamically allocated. This allocates memory for the string when the struct itself is allocated (and will be freed automatically when the struct is freed).

struct *req;  req = malloc(sizeof(*req)+strlen(some_string)+1); req->message = (char *)&req[1]; strcpy(req->message, some_string); 

Freeing

free(req); 

Edit: General Case

Note that the allocation scheme above for the dynamic string is general, it can be used even when you don't know if some_string is a literal or not. Thus, a single function that takes care of both cases, and freeing with free() rids you of special cases.

like image 24
Noah Watkins Avatar answered Sep 27 '22 16:09

Noah Watkins