Concatenate path and basename - c

basename(3) and dirname(3) can split an absolute path into its respective components.
Short of using snprintf(3), is there a natural posix-compliant library call that does the inverse - takes a directory and a filename and concatenates them?
Manually concatenation works fine for me, but can get a little tedious at times.

as far I know there is no such function in POSIX. However in the GNU libc manual there is a nice helper function:
char *concat (const char *str, ...)
{
va_list ap;
size_t allocated = 100;
char *result = (char *) malloc (allocated);
if (result != NULL)
{
char *newp;
char *wp;
va_start (ap, str);
wp = result;
for (s = str; s != NULL; s = va_arg (ap, const char *))
{
size_t len = strlen (s);
/* Resize the allocated memory if necessary. */
if (wp + len + 1 > result + allocated)
{
allocated = (allocated + len) * 2;
newp = (char *) realloc (result, allocated);
if (newp == NULL)
{
free (result);
return NULL;
}
wp = newp + (wp - result);
result = newp;
}
wp = mempcpy (wp, s, len);
}
/* Terminate the result string. */
*wp++ = '\0';
/* Resize memory to the optimal size. */
newp = realloc (result, wp - result);
if (newp != NULL)
result = newp;
va_end (ap);
}
return result;
}
usage:
const char *path = concat(directory, "/", file);

Related

Getting free() invalid pointer error, when reading file and string joining

So I have this function
char *read_file(int fd)
{
char *str;
char *buffer;
int bytes;
buffer = malloc(sizeof(char) * 101);
if (!buffer)
return (NULL);
bytes = read(fd, buffer, 100);
while (bytes != 0)
{
if (bytes == -1)
{
free(buffer);
return (NULL);
}
buffer[bytes] = '\0';
str = ft_strjoin(str, buffer);
bytes = read(fd, buffer, 100);
}
free(buffer);
return (str);
}
It calls this function ft_strjoin
char *ft_strjoin(char *s1, char *s2)
{
char *str;
if (!s1 && !s2)
return (ft_strdup(""));
if (s1 && !s2)
{
str = ft_strdup(s1);
free(s1);
return (str);
}
if (!s1 && s2)
return (ft_strdup(s2));
if (!s2[0])
return (s1);
str = malloc(sizeof(char) * (ft_strlen(s1) + ft_strlen(s2) + 1));
if (!str)
return (NULL);
ft_memmove(str, s1, ft_strlen(s1));
ft_memmove(str + ft_strlen(s1), s2, ft_strlen(s2));
str[ft_strlen(s1) + ft_strlen(s2)] = '\0';
free(s1);
return (str);
}
The reason why I free s1 is because the previous string will be malloced so I free the previous string and return the new string. How ever it's causing an error free() invalid pointer. If I remove the free(s1) at the end of ft_strjoin the error goes away but I need to free the previous string, so what do I do. ft_strdup just mallocs a new string, duplicates the argument, and copies it to the new malloced string and returns the new malloced string. ft_memmove does what memmove does.
Your function can be reduced to:
char *read_file(int fd)
{
char *str = NULL;
struct stat st;
if(fstat(fd, &st) != -1)
{
str = malloc(st.st_size);
if(str)
{
if(read(fd, str, st.st_size) != st.st_size)
{
/* error handling */
}
}
}
return str;
}
ft_strjoin is much too complicated. You should not free any memory in this kind general function. Use memcpy (or your version) to copy.
char *ft_strjoin(const char * restrict s1, const char * restrict s2)
{
char *str;
size_t s1len = s1 ? ft_strlen(s1) : 0, s2len = s2 ? ft_strlen(s2) : 0;
size_t newsize = s1len + s2len + 1;
str = malloc(newsize);
if(str)
{
if(s1) ft_memcpy(str, s1, s1len);
if(s2) ft_memcpy(str + s1len, s2, s2len);
str[newsize - 1] = 0;
}
return str;
}

Free, invalid pointer

I have a program, that splits strings based on the delimiter. I have also, 2 other functions, one that prints the returned array and another that frees the array.
My program prints the array and returns an error when the free array method is called. Below is the full code.
#include "stringsplit.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
unsigned long int getNofTokens(const char *string) {
char *stringCopy;
unsigned long int stringLength;
unsigned long int count = 0;
stringLength = (unsigned)strlen(string);
stringCopy = malloc((stringLength + 1) * sizeof(char));
strcpy(stringCopy, string);
if (strtok(stringCopy, " \t") != NULL) {
count++;
while (strtok(NULL, " \t") != NULL)
count++;
}
free(stringCopy);
return count;
}
char **split_string(const char *str, const char *split) {
unsigned long int count = getNofTokens(str);
char **result;
result = malloc(sizeof(char *) * count + 1);
char *tmp = malloc(sizeof(char) * strlen(str));
strcpy(tmp, str);
char *token = strtok(tmp, split);
int idx = 0;
while (token != NULL) {
result[idx++] = token;
token = strtok(NULL, split);
}
return result;
}
void print_split_string(char **split_string) {
for (int i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (int i = 0; split_string[i] != NULL; i++) {
char *currentPointer = split_string[i];
free(currentPointer);
}
free(split_string);
}
Also, do I need to explicitly add \0 at the end of the array or does strtok add it automatically?
There are some problems in your code:
[Major] the function getNofTokens() does not take the separator string as an argument, it counts the number of words separated by blanks, potentially returning an inconsistent count to its caller.
[Major] the size allocated in result = malloc(sizeof(char *) * count + 1); is incorrect: it should be:
result = malloc(sizeof(char *) * (count + 1));
Storing the trailing NULL pointer will write beyond the end of the allocated space.
[Major] storing the said NULL terminator at the end of the array is indeed necessary, as the block of memory returned by malloc() is uninitialized.
[Major] the copy of the string allocated and parsed by split_string cannot be safely freed because the pointer tmp is not saved anywhere. The pointer to the first token will be different from tmp in 2 cases: if the string contains only delimiters (no token found) or if the string starts with a delimiter (the initial delimiters will be skipped). In order to simplify the code and make it reliable, each token could be duplicated and tmp should be freed. In fact your free_split_string() function relies on this behavior. With the current implementation, the behavior is undefined.
[Minor] you use unsigned long and int inconsistently for strings lengths and array index variables. For consistency, you should use size_t for both.
[Remark] you should allocate string copies with strdup(). If this POSIX standard function is not available on your system, write a simple implementation.
[Major] you never test for memory allocation failure. This is OK for testing purposes and throw away code, but such potential failures should always be accounted for in production code.
[Remark] strtok() is a tricky function to use: it modifies the source string and keeps a hidden static state that makes it non-reentrant. You should avoid using this function although in this particular case it performs correctly, but if the caller of split_string or getNofTokens relied on this hidden state being preserved, it would get unexpected behavior.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
size_t getNofTokens(const char *string, const char *split) {
char *tmp = strdup(string);
size_t count = 0;
if (strtok(tmp, split) != NULL) {
count++;
while (strtok(NULL, split) != NULL)
count++;
}
free(tmp);
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
char *tmp = strdup(str);
char *token = strtok(tmp, split);
size_t idx = 0;
while (token != NULL && idx < count) {
result[idx++] = strdup(token);
token = strtok(NULL, split);
}
result[idx] = NULL;
free(tmp);
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
Here is an alternative without strtok() and without intermediary allocations:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
size_t getNofTokens(const char *str, const char *split) {
size_t count = 0;
size_t pos = 0, len;
for (pos = 0;; pos += len) {
pos += strspn(str + pos, split); // skip delimiters
len = strcspn(str + pos, split); // parse token
if (len == '\0')
break;
count++;
}
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
size_t pos, len, idx;
for (pos = 0, idx = 0; idx < count; pos += len, idx++) {
pos += strspn(str + pos, split); // skip delimiters
len = strcspn(str + pos, split); // parse token
if (len == '\0')
break;
result[idx] = strndup(str + pos, len);
}
result[idx] = NULL;
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
EDIT After re-reading the specification in your comment, there seems to be some potential confusion as to the semantics of the split argument:
if split is a set of delimiters, the above code does the job. And the examples will be split as expected.
if split is an actual string to match explicitly, the above code only works by coincidence on the examples given in the comment.
To implement the latter semantics, you should use strstr() to search for the split substring in both getNofTokens and split_string.
Here is an example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stringsplit.h"
/* Split string by another string, return split parts + NULL in array.
*
* Parameters:
* str: the string to split
* split: the string to split str with
*
* Returns:
* A dynamically reserved array of dynamically reserved string parts.
*
* For example called with "Test string split" and " ",
* returns ["Test", "string", "split", NULL].
* Or called with "Another - test" and " - ",
* returns ["Another", "test", NULL].
*/
size_t getNofTokens(const char *str, const char *split) {
const char *p;
size_t count = 1;
size_t len = strlen(split);
if (len == 0)
return strlen(str);
for (p = str; (p = strstr(p, split)) != NULL; p += len)
count++;
return count;
}
char **split_string(const char *str, const char *split) {
size_t count = getNofTokens(str, split);
char **result = malloc(sizeof(*result) * (count + 1));
size_t len = strlen(split);
size_t idx;
const char *p = str;
for (idx = 0; idx < count; idx++) {
const char *q = strstr(p, split);
if (q == NULL) {
q = p + strlen(p);
} else
if (q == p && *q != '\0') {
q++;
}
result[idx] = strndup(p, q - p);
p = q + len;
}
result[idx] = NULL;
return result;
}
void print_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
printf("%s\n", split_string[i]);
}
}
void free_split_string(char **split_string) {
for (size_t i = 0; split_string[i] != NULL; i++) {
free(split_string[i]);
}
free(split_string);
}
When debugging, take note of values that you got from malloc, strdup, etc. Let's call these values "the active set". It's just a name, so that we can refer to them. You get a pointer from those functions, you mentally add it to the active set. When you call free, you can only pass values from the active set, and after free returns, you mentally remove them from the set. Any other use of free is invalid and a bug.
You can easily find this out by putting breakpoints after all memory allocations, so that you can write down the pointer values, and then breakpoints on all frees, so that you can see if one of those pointer values got passed to free - since, again, to do otherwise is to misuse free.
This can be done also using "printf" debugging. Like this:
char *buf = malloc(...); // or strdup, or ...
fprintf(stderr, "+++ Alloc %8p\n", buf);
And then whenever you have free, do it again:
fprintf(stderr, "--- Free %8p\n", ptr);
free(ptr);
In the output of the program, you must be able to match every +++ with ---. If you see any --- with a value that wasn't earlier listed with a +++, there's your problem: that's the buggy invocation of free :)
I suggest using fprintf(stderr, ... instead of printf(..., since the former is typically unbuffered, so if your program crashes, you won't miss any output. printf is buffered on some architectures (and not buffered on others - so much for consistency).

Trying to replace text in files throws a error

The point of the script is to take three parameters. Find, replace, prefix. Find being the text to replace, replace being what to replace the text with, and prefix is a special case. If prefix is in the text, you replace the prefix (some text) with prefix+replace. I would like to know why the below code throws a error right after saying opened file. It only seems to throw an error if the text being replaced is repeated like "aaa", "bbb" where "a" is what is being replaced.
Opened file.txt
*** Error in `./a.out': malloc(): memory corruption: 0x00005652fbc55980 ***
There's also the occasionally seg fault after printing "Trying to replace for file ...". I'm not fluent in C and GDB on my system resulted in just missing library errors which has nothing to do with this.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
char concat(const char *s1, const char *s2)
{
char *result = calloc(strlen(s1)+strlen(s2)+1, 1);
strcpy(result, s1);
strcat(result, s2);
printf("Prefix will be replaced with %s.\n", result);
return result;
}
static int replaceString(char *buf, const char *find, const char *replace, const char *prefix)
{
int olen, rlen;
char *s, *d;
char *tmpbuf;
if (!buf || !*buf || !find || !*find || !replace)
return 0;
tmpbuf = calloc(strlen(buf) + 1, 1);
if (tmpbuf == NULL)
return 0;
olen = strlen(find);
rlen = strlen(replace);
s = buf;
d = tmpbuf;
while (*s) {
if (strncmp(s, find, olen) == 0) {
strcpy(d, replace);
s += olen;
d += rlen;
}
else
{
*d++ = *s++;
}
}
*d = '\0';
if(strcmp(buf, tmpbuf) == 0)
{
free(tmpbuf);
return 0;
}
else
{
strcpy(buf, tmpbuf);
free(tmpbuf);
printf("%s", buf);
printf("Replaced!\n");
return 1;
}
}
void getAndReplace(char* filename, char* find, char* replace, char* prefix)
{
long length;
FILE* f = fopen (filename, "r");
char* buffer = 0;
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = calloc(length+1, 1); //If i use malloc here, any file other than the first has garbage added to it. Why?
if (buffer)
{
fread(buffer, 1, length, f);
}
fclose(f);
}
if(buffer)// && strlen(buffer) > 1)
{
int result = replaceString(buffer, find, replace, prefix);
if(result == 0)
{
printf("Trying to replace prefix.\n");
replace = concat(prefix, replace);
result = replaceString(buffer, prefix, replace, "");
}
else
{
printf("Successfully replaced %s with %s\n", find, replace);
}
if(result == 1)
{
FILE* fp = fopen(filename, "w+");
if(fp)
{
printf("Opened %s\n", filename);
fprintf(fp, buffer);
fclose(fp);
printf("File %s overwritten with changes.\n", filename);
}
}
else
{
printf("Nothing to replace for %s\n", filename);
}
}
else
{
printf("Empty file.");
}
if(buffer)
{
free(buffer);
}
}
int main(int argc, char **argv)
{
if(argc < 4)
{
printf("Not enough arguments given: ./hw3 <find> <replace> <prefix>\n");
return 1;
}
struct dirent *de;
DIR *dr = opendir(".");
if (dr == NULL)
{
printf("Could not open current directory\n");
return 0;
}
while ((de = readdir(dr)) != NULL)
{
if(strlen(de->d_name) > 4 && !strcmp(de->d_name + strlen(de->d_name) - 4, ".txt"))
{
printf("Trying to replace for file %s\n", de->d_name);
getAndReplace(de->d_name, argv[1], argv[2], argv[3]);
}
}
closedir(dr);
return 0;
}
I hope that you concat function
char concat(const char *s1, const char *s2);
is just a typo and you meant
char *concat(const char *s1, const char *s2);
otherwise the function would be returning a pointer as if it were a char.
Using valgrind would give more details where exactly you are reading/writing where you are not allowed to and
where you are leaking memory. Without that it's hard to pinpoint the exact
place. One thing I noticed is that depending on the length of find and replace,
you might not have enough memory for tmpbuf which would lead to a buffer
overflow.
I think that the best way to write the replaceString is by making it
allocate the memory it needs itself, rather than providing it a buffer to write into.
Because you are getting both find and replace from the user, you don't know
how large the resulting buffer will need to be. You could calculate it
beforehand, but you don't do that. If you want to pass a pre-allocated buffer to
replaceString, I'd pass it as a double pointer, so that replaceString can do
realloc on it when needed. Or allocate the memory in the function and return a
pointer to the allocated memory.
This would be my version:
char *replaceString(const char *haystack, const char *needle, const char *replace)
{
if(haystack == NULL || needle == NULL || replace == NULL)
return NULL;
char *dest = NULL, *tmp;
size_t needle_len = strlen(needle);
size_t replace_len = strlen(replace);
size_t curr_len = 0;
while(*haystack)
{
char *found = strstr(haystack, needle);
size_t copy_len1 = 0;
size_t new_size = 0;
size_t pre_found_len = 0;
if(found == NULL)
{
copy_len1 = strlen(haystack) + 1;
new_size = curr_len + copy_len1;
} else {
pre_found_len = found - haystack;
copy_len1 = pre_found_len;
new_size = curr_len + pre_found_len + replace_len + 1;
}
tmp = realloc(dest, new_size);
if(tmp == NULL)
{
free(dest);
return NULL;
}
dest = tmp;
strncpy(dest + curr_len, haystack, copy_len1);
if(found == NULL)
return dest; // last replacement, copied to the end
strncpy(dest + curr_len + pre_found_len, replace, replace_len + 1);
curr_len += pre_found_len + replace_len;
haystack += pre_found_len + needle_len;
}
return dest;
}
The idea in this version is similar to yours, but mine reallocates the memory as
it goes. I changed the name of the arguments to have the same name as the
strstr function does based on my documentation:
man strstr
char *strstr(const char *haystack, const char *needle);
Because I'm going to update haystack to point past the characters copied, I
use this loop:
while(*haystack)
{
...
}
which means it is going to stop when the '\0'-terminating byte is reached.
The first thing is to use strstr to locate a substring that matches needle.
Base on whether a substring is found, I calculate how much bytes I would need to
copy until the substring, and the new size of the buffer. After that I
reallocate the memory for the buffer and copy everything until the substring,
then append the replacement, update the curr_len variable and update the
haystack pointer to point past the substring.
If the substring is not found, no more replacements are needed. So we have to
copy the string pointed to by haystack and return the constructed string. The
new size of the destination is curr_len + strlen(haystack) + 1 (the +1
because I want the strncpy function to also copy the '\0'-terminating byte).
And it has to copy strlen(haystack) + 1 bytes. After the first strncpy, the
function returns dest.
If the substring is found, then we have to copy everything until the substring,
append the replacement and update the current length and the haystack pointer.
First I calculate the string until the found substring and save it in
pre_found_len. The new size of the destination will be
curr_len + pre_found_len + replace_len + 1 (the current length + length of
string until substring + the length of the replacement + 1 for the
'\0'-terminating byte). Now the first strncpy copies only pre_found_len
bytes. Then it copies the replacement.
Now you can call it like this:
int main(void)
{
const char *orig = "Is this the real life? Is this just fantasy?";
char *text = replaceString(orig, "a", "_A_");
if(text)
{
puts(orig);
puts(text);
}
free(text);
}
which will output:
Is this the real life? Is this just fantasy?
Is this the re_A_l life? Is this just f_A_nt_A_sy?
Now you can use this function in getAndReplace to replace the prefix:
char *getAndReplace(char* filename, char* find, char* replace, char* prefix)
{
...
char *rep1 = replaceString(buffer, find, replace);
if(rep1 == NULL)
{
// error
free(buffer);
return NULL;
}
char *prefix_rep = malloc(strlen(replace) + strlen(prefix) + 1);
if(prefix_rep == NULL)
{
// error
free(buffer);
free(rep1);
return NULL;
}
sprintf(prefix_rep, "%s%s", replace, prefix);
char *rep2 = replaceString(rep1, prefix, prefix_rep);
if(rep2 == NULL)
{
// error
free(buffer);
free(rep1);
free(prefix_rep);
return NULL;
}
// rep2 has all the replacements
...
// before leaving
free(buffer);
free(rep1);
free(prefix_rep);
// returning all replacements
return rep2;
}
When using malloc & co, don't forget to check if they return NULL and don't
forget to free the memory when not needed.

How to create a new char* in standard C

I have this code made for C++ (it works):
char* ConcatCharToCharArray(char *Str, char Chr)
{
char *StrResult = new char[strlen(Str) + 2];
strcpy(StrResult, Str);
StrResult[strlen(Str)] = Chr;
StrResult[strlen(Str) + 1] = '\0';
return StrResult;
}
/* Example: String = "Hello worl"
Char = "d"
Final string = "Hello world" */
The little problem is that I'm making a standard C program in Ubuntu and I need this code.
And "new" is NOT being recognized as a reserved word and there's even a red mark under it.
I tried: char *StrResult[strlen(Str) + 2], but it doesn't work because that way only admits constant values. I'm guessing "malloc" would be the standard C solution in here, how could I do this with "malloc" or any other way for that matter? Thank you so much.
new is the C++ way of allocating memory. In C you're right, you need to use malloc.
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t len = strlen( Str );
char *StrResult = malloc( len + 2 );
/* Check for StrResult==NULL here */
strcpy(StrResult, Str);
StrResult[len] = Chr;
StrResult[len+1] = '\0';
return StrResult;
}
When you're done with the memory, you'd call free( StrResult ).
Yes, you need malloc and you are confusing C with C++ here (since new comes from C++):
char *StrResult = (*char) malloc((strlen(Str) + 2) * sizeof(char));
char takes only one byte (see this question), so you don't need to multiply by it's size:
char *StrResult = (*char) malloc(strlen(Str) + 2);
One way:
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t StrLen = strlen(Str);
char *StrResult = malloc(StrLen + 2);
if(NULL == StrResult)
goto CLEANUP;
strcpy(StrResult, Str);
StrResult[StrLen++] = Chr;
StrResult[StrLen] = '\0';
CLEANUP:
return StrResult;
}
However, the above allocates a new string, instead of concatenating a character to an existing string. Here is a way to expand an existing string with an additional character:
int StrConcatChar(char **string, char character)
{
int rCode=0;
size_t stringLen;
char *temp;
if(NULL == string)
{
rCode=EINVAL;
goto CLEANUP;
}
stringLen = *string ? strlen(*string) : 0;
errno=0;
temp=realloc(*string, stringLen+2);
if(NULL == temp)
{
rCode=errno?errno:ENOMEM;
goto CLEANUP;
}
*string=temp;
(*string)[stringLen++] = character;
(*string)[stringLen] = '\0';
CLEANUP:
return(rCode);
}
The above function might be called like this:
{
int rCode=0;
char *buffer=NULL;
buffer=strdup("Hello worl");
if(NULL == buffer)
/* handle error condition */
rCode=StrConcatChar(&buffer, 'd');
if(rCode)
/* handle error condition */
...
if(buffer)
free(buffer);
}

Memory issue in C where data is being overwritten

I've the following program:
// required include statements...
static char ***out;
char* get_parameter(char* key)
{
char *querystr = /*getenv("QUERY_STRING")*/ "abcdefg=abcdefghi";
if (querystr == NULL)
return (void*)0;
char s[strlen(querystr)] ;
strcpy(s, querystr);
const char delim = '&';
const char delim2 = '=';
static size_t size = 0;
if (out == 0)
{
out = (char*) malloc(sizeof(char*));
size = split(s, &delim, out);
}
int i=0;
for (; i<size; i++)
{
if ((*out)[i] != NULL)
{
char ***iout = NULL;
iout = (char*) malloc(sizeof(char*));
int isize = split((*out)[i], &delim2, iout);
if (isize > 1 && ((*iout)[1]) != NULL && strcmp(key, (*iout)[0]) == 0)
{
size_t _size = strlen((*iout)[1]);
char* value = (char*) malloc(_size*sizeof(char));
strcpy(value, (*iout)[1]);
free(iout);
return value;
}
}
}
return (void*) 0;
}
static size_t count(const char *str, char ch)
{
if (str == NULL) return 0;
size_t count = 1;
while (*str)
if (*str++ == ch) count++;
return count;
}
size_t split(const char *const str, const char* delim, char ***out)
{
size_t size = count(str, *delim);
*out = calloc(size, sizeof(char));
char* token = NULL;
char* tmp = (char*) str;
int i=0;
while ((token = strtok(tmp, delim)) != NULL)
{
tmp = NULL;
(*out)[i] = (char*) malloc(sizeof strlen(token));
strcpy((*out)[i++], token);
}
return size;
}
main()
{
char* val = get_parameter("abcdefg");
printf("%s\n", val); // it should prints `abcdefghi`, but it prints `abcd?`
free(val);
}
as appears in the main method, the function get_parameter should prints abcdefghi, but it prints abcd? where ? is a controls character with value of 17.
Why the reset of string is not printed? I think I mis-used the malloc to allocate appropriate space.
Also, is there any tool that I can use to know the internal representation of memory for my pointers?
You're dealing with C-Strings here. You must consider 1 additional byte for the NULL-termination ('\0')
Therefore:
char s[strlen(querystr)] ;
strcpy(s, querystr);
Is incorrect.
strlen will return 4 for string "abcd" but what you want is to allocate space for "abcd\0"
So you need strlen + 1
The lines
out = (char*) malloc(sizeof(char*));
iout = (char*) malloc(sizeof(char*));
are a problem.
sizeof() returns the number of bytes required to store an object of the given type, in this case, the size of a pointer (to a char). malloc() then allocates that many bytes (apparently 4 bytes on your architecture). To fix this, you need to give malloc the desired string length instead of using sizeof.
Additionally, the line
char* value = (char*) malloc(_size*sizeof(char));
has a completely unnecessary use of sizeof(). sizeof(char) is guaranteed by the standard to be 1.
You should use gdb to run your binary step by step and see what's wrong.
Valgrind is a very good tools, it will tell you what's line overwrite in memory, etc..

Resources