I wrote a tiny program in C. It compile perfectly and works, when I compile it through my Makefile and clang, however, in Xcode this function behaves not like it should (or it behaves like it should and clang is ignoring it).
size_t getUrlForArgAndPlatform(char **dest, const char *arg, const char *platform) {
int isLinux = strcmp(platform, "Linux");
int isOSX = strcmp(platform, "Darwin");
char *platformUrlDelimiter = malloc(6 + 1);
if (isLinux == 0) {
strcpy(platformUrlDelimiter, "linux");
} else if (isOSX == 0) {
strcpy(platformUrlDelimiter, "osx");
} else {
strcpy(platformUrlDelimiter, "common");
}
int length = (int) strlen(kBaseUrl);
length += strlen(platformUrlDelimiter);
length += strlen(arg);
length += 5;
char *buffer = (char *) malloc(length);
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
strcpy(buffer, kBaseUrl);
strcat(buffer, "/");
strcat(buffer, platformUrlDelimiter);
strcat(buffer, "/");
strcat(buffer, arg);
strcat(buffer, ".md");
*dest = malloc(strlen(buffer) + 1);
strcpy(*dest, buffer);
free(platformUrlDelimiter);
free(buffer);
return strlen(buffer) + 1;
}
It works 4 times out of 10. In the other 6 times, Xcode is telling me it's failing at strcpy(*dest, buffer) with a SIGBRT. If I take a look at the debugger, I see that buffer contains the same string twice. Why?
The size you have calculated for buffer is not quite correct:
int length = (int) strlen(kBaseUrl);
length += strlen(platformUrlDelimiter);
length += strlen(arg);
length += 5;
The last part should be '+6' because you need space for 2 times "/", for ".md" AND for the terminating NUL.
(The incorrect length has already been mentioned.)
There is a lot of pointless copying going on in your code. Since you don't modify platformUrlDelimiter, there is no need to copy it twice. This is much simpler:
const char *platformUrlDelimiter = "common";
if (isLinux == 0) {
platformUrlDelimiter = "linux";
} else if (isOSX == 0) {
platformUrlDelimiter = "osx";
}
And remove the call to free (platformUrlDelimiter).
Every call to strcat() (probably) has to needlessly loop through the buffer. I would write:
int length = strlen(kBaseUrl)
+ strlen(platformUrlDelimiter)
+ strlen(arg)
+ 6;
*dest = malloc(length);
if (*dest) {
sprintf (*dest, "%s/%s/%s.md", kBaseUrl, platformUrlDelimiter, arg);
} else {
/* Error */
}
return length;
Now there is no need to use buffer at all.
Also, there's a real bug right at the end of your code:
free(buffer);
return strlen(buffer) + 1;
You must not use the value of buffer in any way after it has been freed.
Related
I'm still writing my own implementation of get_next_line, a function that takes a file descriptor and outputs the line of the file, then the next line and so on, since my last post, but now everything is working in my code !
The problem is, in the norms I have to follow, my code have to be less than 25 lines, and my function is actually 30. I successfully split into one sub function but I need to split it one more time but this time, I get invalid frees or invalid reads and completely wrong results.
(I have a get_next_line_utils.c that contains homemade libc functions and it has a strjoin that frees the stash in parameter because it creates a new one)
Here is my working code :
static int check_line(char *str)
{
int i;
i = 0;
if (!str)
return (-1);
while (str[i])
{
if (str[i] == '\n')
return (1);
i++;
}
return (-1);
}
/*
ft_strcut is used in one case in GNL.
When the stash contains a \n, we are cutting the string
from the \n to the end of the string, so our new stash does not
longer contain the \n ans the past line.
*/
static char *ft_strcut(char *str)
{
char *cutted_str;
int i;
int j;
i = 0;
j = 0;
while (str[i] != '\n')
i++;
cutted_str = malloc(sizeof(char) * (ft_strlen(str) - i + 1));
if (!cutted_str)
return (NULL);
i++;
while (str[i])
cutted_str[j++] = str[i++];
cutted_str[j] = '\0';
free(str);
return (cutted_str);
}
/*
I used this function to make GNL less than 25 lines.
This block of code was between the variable declaration and the while loop.
This function is checking the validity of fd, BUFFER_SIZE and the stash.
And it's initializing our stash for the rest of GNL if the verification passed.
*/
static char *stash_checking(int fd, char *stash, char *buff, int readed)
{
if (fd < 0 || BUFFER_SIZE <= 0)
return (NULL);
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
if (!buff)
return (NULL);
readed = read(fd, buff, BUFFER_SIZE);
if (readed <= 0 && !stash)
{
free(buff);
return (NULL);
}
buff[readed] = '\0';
if (!stash)
stash = ft_substr(buff, 0, ft_strlen(buff)); //It's like strdup
else
stash = ft_strjoin(stash, buff);
free(buff);
if (stash[0] == '\0')
{
free(stash);
stash = NULL;
return (NULL);
}
return (stash);
}
char *get_next_line(int fd)
{
static char *stash; //Static variable to keep the stash between calls.
char *buff; //Buffer to read the file.
char *line; //Line to return.
int readed; //Readed bytes.
readed = 0;
buff = NULL;
stash = stash_checking(fd, stash, buff, readed);
while (stash)
{
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
readed = read(fd, buff, BUFFER_SIZE);
buff[readed] = '\0';
stash = ft_strjoin(stash, buff);
free(buff);
if (readed < BUFFER_SIZE && check_line(stash) == -1)
{
line = ft_substr(stash, 0, ft_strlen(stash)); //It's like strdup
free(stash);
stash = NULL;
return (line);
}
else if (check_line(stash) != -1)
{
line = ft_substr(stash, 0, ft_strchr(stash, '\n') - stash + 1);
stash = ft_strcut(stash);
return (line);
}
}
return (NULL);
}
As you can see, I successfully split a chunk of code into a function named stash_checking to make my code shorter but it is not enough.
I tried to put the lines from if (readed < BUFFER_SIZE && check_line(stash) == -1) to the end of else if
in a sub function that I named handling_cases and I'm getting a double free() error.
static char *handling_cases(int readed, char *stash, char *line)
{
if (readed < BUFFER_SIZE && check_line(stash) == -1)
{
line = ft_substr(stash, 0, ft_strlen(stash));
free(stash);
stash = NULL;
return (line);
}
else if (check_line(stash) != -1)
{
line = ft_substr(stash, 0, ft_strchr(stash, '\n') - stash + 1);
stash = ft_strcut(stash);
return (line);
}
return (NULL);
}
char *get_next_line(int fd)
{
static char *stash; //Static variable to keep the stash between calls.
char *buff; //Buffer to read the file.
char *line; //Line to return.
int readed; //Readed bytes.
readed = 0;
buff = NULL;
stash = stash_checking(fd, stash, buff, readed);
while (stash)
{
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
readed = read(fd, buff, BUFFER_SIZE);
buff[readed] = '\0';
stash = ft_strjoin(stash, buff);
free(buff);
line = handling_cases(readed, stash, line);
if (line)
return (line);
}
return (NULL);
}
I have tested a lot of similar things, putting all the while loop in a sub function that returns the line and many different things but I don't understand why, I'm getting some double frees, invalid write or not expected output.
I would like to understand why putting the exact chunk of code in a separate function is doing errors.
I debugged my code, and it seem's my stash is not correctly freed, or always have no values in it when I call GNL at the end of the file.
I'm sorry if this is a little confusing, my english is not perfect yet..
Any help is much appreciated !
Your approach with passing stash is kind-of correct, but you missed one thing: You need to pass a pointer to the variable to a called function. This resembles "pass by reference" in C, which only has "pass by value".
It does not matter, whether such a variable is static or not. The called function does not need to know, and you cannot make it know.
I have simplified your example and used generic names:
#include <stdio.h>
#include <stdlib.h>
static void called(int **pointer_to_pointer) {
int value = 42;
if (*pointer_to_pointer != NULL) {
value = **pointer_to_pointer;
//free(*pointer_to_pointer);
}
*pointer_to_pointer = malloc(sizeof **pointer_to_pointer);
**pointer_to_pointer = value + 1;
printf("%s(): %p -> %p -> %d\n", __FUNCTION__, (void*)pointer_to_pointer, (void*)*pointer_to_pointer, **pointer_to_pointer);
}
static void caller(void) {
static int *pointer = NULL;
int value = 23;
if (pointer != NULL) {
value = *pointer;
//free(pointer);
}
pointer = malloc(sizeof *pointer);
*pointer = value + 1;
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
called(&pointer);
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
called(&pointer);
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
}
int main(void) {
printf("%s()\n", __FUNCTION__);
caller();
printf("%s()\n", __FUNCTION__);
caller();
printf("%s()\n", __FUNCTION__);
}
Some notes:
Because in my environment malloc() returned exactly the same memory that was just free()ed, I needed to comment those calls to show that new memory was allocated.
The size in the calls of malloc() uses the sizeof operator with the expression that "is" the wanted object. You can keep using the parenthesized version of this operator with a data type, like sizeof (int) for this demonstration program.
Here is no error check after calling malloc(). Don't do this in production code.
__FUNCTION__ is a nice predefined preprocessor macro of GCC and Clang, which expands to the name of the current function as a C string.
printf() expects void* for its format specifier "%p", so every pointer value is correctly cast.
My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.
The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '\0' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.
Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.
Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.
When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.
Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.
Edit: should mention that with the following code,
ret[c] = buffer;
printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);
it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEBUG
#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif
char **str_split(char[], char, int*);
int count_char(char[], char);
int main(void) {
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);
if (result == NULL) {
printf("result is NULL\n");
return 0;
}
if (num_strings > 0) {
for (int i = 0; i < num_strings; i++) {
printf("\"%s\" \n", result[i]);
}
}
free(result);
return 0;
}
char **str_split(char string[], char delim, int *num_strings) {
int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;
if (*num_strings < 2) {
return NULL;
}
//return value
char **ret = malloc((*num_strings) * sizeof(char*));
if (ret == NULL) {
_D printf("ret is null.\n");
return NULL;
}
int slen = strlen(string);
char buffer[slen];
/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++) {
char cur = string[i];
if (cur == delim || cur == '\0') {
_D printf("Copying content of buffer to ret[%i]\n", c);
//char *tmp = malloc(sizeof(char) * slen + 1);
//strcpy(tmp, buffer);
//ret[c] = tmp;
ret[c] = buffer;
_D printf("Content of ret[%i] = \"%s\" \n", c, ret[c]);
//free(tmp);
c++;
b = 0;
continue;
}
//otherwise
_D printf("{%i} Copying char[%c] to index [%i] of buffer\n", c, cur, b);
buffer[b] = cur;
buffer[b+1] = '\0'; /* extend the null char */
b++;
_D printf("Buffer is now equal to: \"%s\"\n", buffer);
}
return ret;
}
int count_char(char base[], char c) {
int count = 0;
int i = 0;
while (base[i] != '\0') {
if (base[i++] == c) {
count++;
}
}
_D printf("Found %i occurence(s) of '%c'\n", count, c);
return count;
}
You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.
To get around this requires one of the following:
Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:
char my_string[] = "Helo_World_poopy_pants";
char **result = str_split(my_string, '_', &num_strings);
In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).
Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.
It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.
Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:
When you allocate the pointer array, also make it large enough to hold a copy of the string:
// Allocate storage for `num_strings` pointers, plus a copy of the original string,
// then copy the string into memory immediately following the pointer storage.
char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
char *buffer = (char*)&ret[*num_strings];
strcpy(buffer, string);
Now, do all your string operations on buffer. For example:
// Extract all delimited substrings. Here, buffer will always point at the
// current substring, and p will search for the delimiter. Once found,
// the substring is terminated, its pointer appended to the substring array,
// and then buffer is pointed at the next substring, if any.
int c = 0;
for(char *p = buffer; *buffer; ++p)
{
if (*p == delim || !*p) {
char *next = p;
if (*p) {
*p = '\0';
++next;
}
ret[c++] = buffer;
buffer = next;
}
}
When you need to clean up, it's just a single call to free, because everything was stored together.
The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().
Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?
Here is a simpler implementation:
#include <stdlib.h>
char **str_split(const char *string, char delim, int *num_strings) {
int i, n, from, to;
char **res;
for (n = 1, i = 0; string[i]; i++)
n += (string[i] == delim);
*num_strings = 0;
res = malloc(sizeof(*res) * n);
if (res == NULL)
return NULL;
for (i = from = to = 0;; from = to + 1) {
for (to = from; string[to] != delim && string[to] != '\0'; to++)
continue;
res[i] = malloc(to - from + 1);
if (res[i] == NULL) {
/* allocation failure: free memory allocated so far */
while (i > 0)
free(res[--i]);
free(res);
return NULL;
}
memcpy(res[i], string + from, to - from);
res[i][to - from] = '\0';
i++;
if (string[to] == '\0')
break;
}
*num_strings = n;
return res;
}
I have a function which choose and extract a JSON line. This JSON line will be computed in another function which is supposed to extract the value of it.
"key" : "value",
I wish to extract value without using any library made to manipulate JSON.
My code looks like this so far :
char* extractValueInLine(char* line) {
if(!verifyLine(line)) // Checks wether line contains 4 quotes or not
return "";
int len = strlen( line );
char* res = NULL;
unsigned quoteCpt = 0;
for (unsigned i = 0; i < len; i++){
if (line[i] == '\"')
quoteCpt++;
if (quoteCpt == 3) // If 3 quotes has been skipped
{
res = malloc((char) sizeof(res) + sizeof(char)); // Adding memory for one char
if (NULL == res)
fprintf(stderr, "Not enough memory.\n");
else
{
char toAppend[2];
toAppend[1] = '\0';
toAppend[0] = line[i];
strcat(res, toAppend); // Append current char
}
}
return res;
}
This is very ugly and not efficient at all since the output is blank instead of being value.
Nevertheless I have tried more and more ways to do this, using string library functions and with sscanf, strtok and stuff but it was either not working or easily breakable.
A code which could work even if a blank space were added or missing would be perfect.
If anyone could advise me or tell me what I am missing here.
Use strchr() to find the position of the quotes. Then, with that information extract the value.
Something like
char *q1 = strchr(line, '\"'); /* needs error checking */
char *q2 = strchr(q1 + 1, '\"');
char *q3 = strchr(q2 + 1, '\"');
char *q4 = strchr(q3 + 1, '\"');
/* allocate (q4 - q3) bytes for res */
sprintf(res, "%.*s", (int)(q4 - q3 - 1), q3 + 1);
The issues with your code
Missing one } which makes your code return in the first iteration itself.
You are allocating new space every time. Which makes it lose the previous contents.
The fix would be
char* extractValueInLine(char* line) {
int len = strlen( line );
char* res = malloc(1);
res[0] = '\0';
unsigned quoteCpt = 0;
for (unsigned i = 0; i < len; i++){
if (line[i] == '\"')
quoteCpt++;
else if (quoteCpt == 3) {
res = realloc(res, strlen(res) + sizeof(char) + 1); // Free memory for additional char
if (NULL == res)
fprintf(stderr, "Not enough memory.\n");
else{
char toAppend[2];
toAppend[1] = '\0';
toAppend[0] = line[i];
strcat(res, toAppend);
}
}
}
return res;
}
The main change is that I have used realloc instead of malloc which copies the previous contents and frees the old buffer.
You can see the demo at Ideone
I'm reading bytes from a socket and copying it into a char array.
char usrInputStr[256];
if ((rbytes = read(STDIN_FILENO, usrInputStr, 256)) < 0) {
perror("Read error: ");
exit(-1);
}
char finalStr[rbytes + 1];
memcpy(finalStr, usrInputStr, rbytes);
Now I allot an array on the heap and split the string into words and put each word in an array of char arrays. This is the code that does that.
char** currentTokens = (char**)malloc(sizeof(char*) * 256);
for(int i = 0; i < 256; i++) {
currentTokens[i] = (char*)malloc(sizeof(char) * 256);
}
int sz = splitStrToArray(finalStr, currentTokens);
The definition of the splitStrToArray function is here,this works fine.
int splitStrToArray(char* str, char** arr) {
int count = 0;
char* buffer;
int len = strlen(str);
for (int i = 0; i < len ; ++i) {
if(isspace(str[i])) {
count++;
}
}
int index = 0;
buffer = strtok(str, " ");
while(buffer != NULL) {
memcpy(arr[index], buffer, strlen(buffer));
index++;
buffer = strtok(NULL, " ");
}
return count;
}
However when I compare this with user input it doest return zero and thus the two string don't match.
if(strncasecmp(currentTokens[0], "quit") == 0) {
printf("quit" );
breakTrigger = 1;
} else if(strcasecmp(currentTokens[0], "q") == 0) {
printf("q");
breakTrigger = 1;
} else {
callback(currentTokens, sz, port);
}
I've checked currentTokens[0] and the word is correct.
When the I try to take the return value of strcasecmp in an int and print it I get Segmentation Fault.
I'm new to C, any help appreciated.
None of your strings are null-terminated so you have undefined behaviour throughout. Using memcpy to copy strings is almost never what you want.
You should consider using strdup, if available. Otherwise malloc and then strcpy.
In the particular case of finalStr, I see no good reason to perform the copy at all. Just read directly into it (and don't forget to null-terminate.) Alternatively, use the standard C library instead of the underlying posix layer.
I am trying to implement function to split strings, but i keep getting segmentation faults. I am working on Windows XP, and therefore i also had to implement strdup(), because Windows API doesn't provide it. Can anyone tell me what's wrong with the following piece of code.
char** strspl(char* str, char* del)
{
int size = 1;
for(int i = 0; i < strlen(str);) {
if(strncmp(str + i, del, strlen(del)) == 0) {
size++;
i += strlen(del);
}
else {
i++;
}
}
char** res = (char**)malloc(size * sizeof(char*));
res[0] = strdup(strtok(str, del));
for(int i = 0; res[i] != NULL; i++) {
res[i] = strdup(strtok(NULL, del));
}
return res;
}
char* strdup(char* str) {
char* res = (char*)malloc(strlen(str));
strncpy(res, str, sizeof(str));
return res;
}
EDIT: using a debugger i found out, that program crashes after following line:
res[0] = strdup(strtok(str,del));
Also, i fixed strdup(), but there is still no progress.
You're not counting the null terminator and you are copying the wrong number of bytes
char* strdup(char* str) {
char* res = (char*)malloc(strlen(str)); /* what about the null terminator? */
strncpy(res, str, sizeof(str)); /* sizeof(str)
** is the same as
** sizeof (char*) */
return res;
}
Your strdup() function is not correct. The sizeof(str) in there is the size of the str pointer (probably 4 or 8 bytes), not the length of the string. Use the library provided _strdup() instead.
malloc does not initialize the allocated memory to \0. Have you tried using calloc instead? I suspect the seg faults are due to the res[i] != NULL comparison.
There are many things wrong with this code, but the main flaw is trying to implement this function. It will only provide you with marginal benefit, if any.
Compare the following two code snippets:
/* Using strtok... */
char *tok = strtok(str, del);
while (tok != NULL) {
/* Do something with tok. */
tok = strtok(NULL, del);
}
-
/* Using your function... */
char **res = strspl(str, del, &size);
size_t i;
for (i = 0; i < size; i++) {
/* Do something with *(res + i). */
}