This smells like a heap corruption of some kind but I can not seem to find it.
the problem occurs on string_utils_replace() when trying to run free(tmp_for_free). the function is supposed to replace every occurrence of "search" with "replace" in "string".
char* string_utils_part_of_string(char *string, int from, int to)
{
int size_to_allocate = to - from + 1;
char *result = (char*)malloc(sizeof(char) * size_to_allocate);
strncpy(result, string + from, to - from);
result[size_to_allocate - 1] = '\0';
return result;
}
char* string_utils_replace(char *search, char *replace, char *string)
{
char *end, *result = string, *tmp_for_free = NULL;
int before_replace, after_replace;
int size_search = strlen(search);
int size_replace = strlen(replace);
int size_string, size_find;
int first_time = 1;
char *find = strstr(string, search);
if (find == NULL)
return string_utils_copy_string(string);
while (find != NULL)
{
tmp_for_free = result;
size_string = strlen(result);
size_find = strlen(find);
before_replace = size_string - size_find;
after_replace = before_replace + size_replace;
end = string_utils_part_of_string(result, after_replace, size_string);
result = string_utils_part_of_string(result, 0, before_replace);
strcat(result, replace);
strcat(result, end);
// no memory leaks, hooray!
free(end);
if (first_time == 0)
free(tmp_for_free);
size_string = strlen(result);
find = strstr(result, search);
first_time = 0;
}
return result;
}
any ideas?
As per the man page of strcat(),
char *strcat(char *dest, const char *src);
[..] and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable;
In your string_utils_part_of_string() function, you did not allocate enough memory to the result to be able to hold the entire input, and later, you're trying to use the same pointer to store the whole input, through strcat(). This is creating the memory overrun which in turn invokes undefined behaviour.
Note: Please do not cast the return value of malloc() and family in C.
You are causing a buffer overflow here:
result = string_utils_part_of_string(result, 0, before_replace);
strcat(result, replace);
strcat(result, end);
result is allocated exactly before_replace+1 bytes and initialized with before_replace bytes from the beginning of string and a final '\0'. You cannot concatenate replace and end to this array, it is full already.
The logic in your function is convoluted. You should simplify it. For instance, you should first run a loop counting the number of occurrences of find in string, then allocate a buffer for the result, then run a second loop copying fragments of string and copies of replace.
You should also test if find is an empty string. strstr() will always find the empty string, causing your algorithm to loop endlessly.
Related
I'm trying to add a character at a defined position. I've created a new function, allocate a memory for one more char, save characters after the position then added my character at the defined position, and now I don't know how to erase characters after that position to concatenate the saved string. Any solution?
Here is the beginning of my function:
void appendCharact(char *source, char carac, int position) {
source = realloc(source, strlen(source) * sizeof(char) + 1); //Get enough memory
char *temp = source.substr(position); //Save characters after my position
source[position] = carac; //Add the character
}
EDIT :
I'm trying to implement another "barbarous" solution, in debug mode I can see that I've approximately my new string but it look like I can't erase the older pointer...
void appendCharact(char *source, char carac, int position) {
char *temp = (char *)malloc((strlen(source) + 2) * sizeof(char));
int i;
for(i = 0; i < position; i++) {
temp[i] = source[i];
}
temp[position] = carac;
for (i = position; i < strlen(source); i++) {
temp[i + 1] = source[i];
}
temp[strlen(temp) + 1] = '\0';
free(source);
source = temp;
}
I mentioned that I could see five problems with the code as shown (copied here for reference)
void appendCharact(char * source, char carac , int position)
{
source = realloc(source, strlen(source) * sizeof(char) + 1); //Get enough memory
char * temp = source.substr(position); //Save characters after my position
source[position] = carac; //Add the charactere
}
The problems are (in no specific order):
strlen(source) * sizeof(char) + 1 is equal to (strlen(source) * sizeof(char)) + 1. It should have been (strlen(source) + 1) * sizeof(char). However, this works fine since sizeof(char) is defined in the C++ specification to always be equal to 1.
Related to the above: Simple char strings are really called null-terminated byte strings. As such they must be terminated by a "null" character ('\0'). This null character of course needs space in the allocated string, and is not counted by strlen. Therefore to add a character you need allocate strlen(source) + 2 characters.
Never assign back to the pointer you pass to realloc. If realloc fails, it will return a null pointer, making you lose the original memory, and that is a memory leak.
The realloc function return type is void*. In C++ you need to cast it to the correct pointer type for assignment.
You pass source by value, meaning inside the function you have a local copy of the pointer. When you assign to source you only assign to the local copy, the original pointer used in the call will not be modified.
Here are some other problems with the code, or its possible use:
Regarding the null-terminator, once you allocate enough memory for it you also need to add it to the string.
If the function is called with source being a literal string or an array or anything that wasn't returned by a previous call to malloc, calloc or realloc, then you can't pass that pointer to realloc.
You use source.substr(position) which is not possible since source isn't an object and therefore doesn't have member functions.
Your new solution is much closer to a working function but it still has some problems:
you do not check for malloc() failure.
you should avoid computing the length of the source string multiple times.
temp[strlen(temp) + 1] = '\0'; is incorrect as temp is not yet a proper C string and strlen(temp) + 1 would point beyond the allocated block anyway, you should just write temp[i + 1] = '\0';
the newly allocated string should be returned to the caller, either as the return value or via a char ** argument.
Here is a corrected version:
char *insertCharact(char *source, char carac, size_t position) {
size_t i, len;
char *temp;
len = source ? strlen(source) : 0;
temp = (char *)malloc(len + 2);
if (temp != NULL) {
/* sanitize position */
if (position > len)
position = len;
/* copy initial portion */
for (i = 0; i < position; i++) {
temp[i] = source[i];
}
/* insert new character */
temp[i] = carac;
/* copy remainder of the source string if any */
for (; i < len; i++) {
temp[i + 1] = source[i];
}
/* set the null terminator */
temp[i + 1] = '\0';
free(source);
}
return temp;
}
int pos = 1;
char toInsert = '-';
std::string text = "hallo";
std::stringstream buffer;
buffer << text.substr(0,pos);
buffer << toInsert;
buffer << text.substr(pos);
text = buffer.str();
Try using something like:
#include <string>
void appendCharAt(std::string& src, char c , int pos)
{
std::string front(src.begin(), src.begin() + pos - 1 ); // use iterators
std::string back(src.begin() + pos, src.end() );
src = front + c + back; // concat together +-operator is overloaded for strings
}
Not 100% sure weather the positions are right. Maybe front hast to be src.begin() + pos and back src.begin() + pos + 1. Just try it out.
The C version of this will have to take care of the situation where realloc fails, in which case the original string is preserved. You should only overwrite the old pointer with the one returned from realloc upon success.
It might look something like this:
bool append_ch (char** str, char ch, size_t pos)
{
size_t prev_size = strlen(*str) + 1;
char* tmp = realloc(*str, prev_size+1);
if(tmp == NULL)
{
return false;
}
memmove(&tmp[pos+1], &tmp[pos], prev_size-pos);
tmp[pos] = ch;
*str = tmp;
return true;
}
Usage:
const char test[] = "hello word";
char* str = malloc(sizeof test);
memcpy(str, test, sizeof test);
puts(str);
bool ok = append_ch(&str, 'l', 9);
if(!ok)
asm ("HCF"); // error handling here
puts(str);
free(str);
Implement the append function that has the prototype below. The function returns a string that represents the concatenation of all the strings present in an array of strings. For this problem, you can assume the end of the parameter array is marked by NULL. You need to allocate memory for the resulting string. You may not modify the array parameter.
char* append(char *data[]);
I don't understand how to determine the size to malloc the pointer.
First of all, to know the size of one string, you can use strlen from the library string.h. If you want to calculate the sum of all the sizes you can just use a loop and sum up all the strlens, and add 1 for the terminal NUL character, like this:
char* append(char *data[]) {
char **cur, *res;
size_t len = 0;
for (cur = data; *cur != NULL; *cur++)
len += strlen(*cur);
res = malloc(len + 1);
// Now you can concatenate the strings...
}
Oh, and don't forget to check that the pointer returned by malloc is valid (i.e. not NULL).
An approach that goes through the strings twice seems good.
The first pass counts the sum of the lengths:
size_t len = 0;
for (char** pstr = data; *pstr; pstr++)
len += strlen(*pstr);
The second pass concatenates all the strings:
char *str = malloc(len + 1);
str[0] = '\0';
for (char** pstr = data; *pstr; pstr++)
strcat(str, *pstr);
return str;
You can optimize the concatenation part by storing the end point of the last concatenation:
char *str = malloc(len + 1);
str[0] = '\0';
char *p = str;
for (char** pstr = data; *pstr; pstr++) {
strcat(p, *pstr);
p += strlen(*pstr);
}
I have writen a code to split the string with multiple char delimiter.
It is working fine for first time of calling to this function
but i calling it second time it retuns the correct word with some unwanted symbol.
I think this problem occurs because of not clearing the buffer.I have tried a lot but cant solve this. please help me to solve this problem.
char **split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist= malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
arraylist[i]=malloc(sizeof(buf));
arraylist[i]=buf;
i++;
loc = loc+length;
loc1 = loc;
}
return arraylist;
}
called this function first time
char **splitdetails = split("100000000<delimit>0<delimit>hellooo" , "<delimit>");
It gives
splitdetails[0]=100000000
splitdetails[1]=0
splitdetails[2]=hellooo
but i called this second time
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
splitdetails[0]=20000000��������������������������
splitdetails[1]=10����
splitdetails[2]=testing
Update:-
thanks to #fatelerror. i have change my code as
char** split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist = malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(strlen(loc1) + 1);
strcpy(arraylist[i], loc1);
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
buf[loc - loc1] = '\0';
arraylist[i]=malloc(strlen(buf));
strcpy(arraylist[i], buf);
i++;
loc = loc+length;
loc1 = loc;
}
}
In the caller function, i used it as
char *id
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
id = splitdetails[0];
//some works done with id
//free the split details with this code.
for(int i=0;i<3;i++) {
free(domaindetails[i]);
}free(domaindetails);
domaindetails=NULL;
then i called the same for the second as,
char **splitdetails1= split("10000000<delimit>1000<delimit>testing1" , "<delimit>");
it makes error and i can't free the function.
thanks in advance.
Your problem boils down to three basic things:
sizeof is not strlen()
Assignment doesn't copy strings in C.
strncpy() doesn't always nul-terminate strings.
So, when you say something like:
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
thisdoes not copy the string. The first one allocates the size of loc1, which is a char *. In other words, you allocated the size of a pointer. You want to allocate storage to store the string, i.e. using strlen():
arraylist[i]=malloc(strlen(loc1) + 1);
Note the + 1 as well, because you also need room for the nul-terminator. Then, to copy the string you want to use strcpy():
strcpy(arraylist[i], loc1);
The way you had it was just assigning a pointer to your old string (and in the process leaing the memory you had just allocated). It's also common to use strdup() which combines both of these steps, i.e.
arraylist[i] = strdup(loc1);
This is convenient but strdup() is not part of the official C library. You need to assess the portability needs of your code before you consider using it.
Additionally, with strncpy(), you should be aware that it does not always nul-terminate:
strncpy(buf, loc1, loc-loc1);
This copies less bytes than were in the original string and doesn't terminate buf. Thus, it's necessary to include a nul terminator yourself:
buf[loc - loc1] = '\0';
This is the root cause of what you are seeing with the garbage. Since you didn't nul terminate, C doesn't know where your string ends and so it keeps on reading whatever happens to be in memory.
For reasons that I promise exist, I'm reading input character by character, and if a character meets certain criteria, I'm writing it into a dynamically allocated buffer. This function adds the specified character to the "end" of the specified string. When reading out of the buffer, I read the first 'size' characters.
void append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = (char*)realloc(str,sizeof(char)*(size + 1));
str[size] = c;
}
This function, through various iterations of development has produced such errors as "corrupted double-linked list", "double free or corruption". Below is a sample of how append is supposed to be used:
// buffer is a string
// bufSize is the number of non-garbage characters at the beginning of buffer
char *buft = buffer;
int bufLoc=0;
while((buft-buffer)/sizeof(char) < bufSize)
append(*(buft==),destination,bufLoc++);
It generally works for some seemingly arbitrary number of characters, and then aborts with error. If it's not clear what the second code snippet is doing, it's just copying from the buffer into some destination string. I know there's library methods for this, but I need a bit finer control of what exactly gets copied sometimes.
Thanks in advance for any insight. I'm stumped.
This function does not append a character to a buffer.
void append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = realloc(str, size + 1);
str[size] = c;
}
First, what is strlen(str)? You can say "it's the length of str", but that's omitting some very important details. How does it compute the length? Easy -- str must be NUL-terminated, and strlen finds the offset of the first NUL byte in it. If your buffer doesn't have a NUL byte at the end, then you can't use strlen to find its length.
Typically, you will want to keep track of the buffer's length. In order to reduce the number of reallocations, keep track of the buffer size and the amount of data in it separately.
struct buf {
char *buf;
size_t buflen;
size_t bufalloc;
};
void buf_init(struct buf *b)
{
buf->buf = NULL;
buf->buflen = 0;
buf->bufalloc = 0;
}
void buf_append(struct buf *b, int c)
{
if (buf->buflen >= buf->bufalloc) {
size_t newalloc = buf->bufalloc ? buf->bufalloc * 2 : 16;
char *newbuf = realloc(buf->buf, newalloc);
if (!newbuf)
abort();
buf->buf = newbuf;
buf->bufalloc = newalloc;
}
buf->buf[buf->buflen++] = c;
}
Another problem
This code:
str = realloc(str, size + 1);
It only changes the value of str in append -- it doesn't change the value of str in the calling function. Function arguments are local to the function, and changing them doesn't affect anything outside of the function.
Minor quibbles
This is a bit strange:
// Weird
x = (char*)realloc(str,sizeof(char)*(size + 1));
The (char *) cast is not only unnecessary, but it can actually mask an error -- if you forget to include <stdlib.h>, the cast will allow the code to compile anyway. Bummer.
And sizeof(char) is 1, by definition. So don't bother.
// Fixed
x = realloc(str, size + 1);
When you do a:
str = (char*)realloc(str,sizeof(char)*(size + 1));
the changes in str will not be reflected in the calling function, in other words the changes are local to the function as the pointer is passed by value. To fix this you can either return the value of str:
char * append(char c, char *str, int size)
{
if(size + 1 > strlen(str))
str = (char*)realloc(str,sizeof(char)*(size + 1));
str[size] = c;
return str;
}
or you can pass the pointer by address:
void append(char c, char **str, int size)
{
if(size + 1 > strlen(str))
*str = (char*)realloc(*str,sizeof(char)*(size + 1));
(*str)[size] = c;
}
I need to construct a path to a file from two strings. I could use this (not tested, though):
/* DON'T USE THIS CODE! */
/* cmp means component */
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
unsigned len = strlen(path_cmp1);
char *path = path_cmp1;
for (int i = 0; i < strlen(path_cmp2); i++) {
path[len + i] = path_cmp2[i];
}
but this could lead to memory corruption I guess. Is there a better way to do this, or is there a function for this in the standard library?
#include <stdlib.h>
#include <string.h>
char *join(const char* s1, const char* s2)
{
char* result = malloc(strlen(s1) + strlen(s2) + 1);
if (result) // thanks #pmg
{
strcpy(result, s1);
strcat(result, s2);
}
return result;
}
This is simple enough to be written in place, especially when you have multiple strings to concatenate.
Note that these functions return their destination argument, so you can write
char* result = malloc(strlen(s1) + strlen(s2) + 1);
assert(result);
strcat(strcpy(result, s1), s2);
but this is less readable.
#include <stdio.h>
char *a = "hello ";
char *b = "goodbye";
char *joined;
asprintf(&joined, "%s%s", a, b)
There are several problems in this code:
1 - calling strlen on the for loop is a bad idea, it will calculate the string length every iteration, so it is better to call it once before the loop and keep the result in a variable.
2 - The same strlen problem applies to strlen(path_cmp1) inside the loop, call it before the loop and increments its size.
In the end, it is better to simple copy both strings and store those on a dynamic allocated string, like:
char *join_strings(const char* s1, const char* s2)
{
size_t lens1 = strlen(s1);
size_t lens2 = strlen(s2);
//plus 1 for \0
char *result = malloc(lens1 + lens2 + 1);
if(result)
{
memcpy(result, s1, lens1);
memcpy(result+lens1, s2, lens2+1);
}
//do not forget to call free when do not need it anymore
return result;
}
There are strcat and strncat for that.
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
int firstLength = strlen(path_cmp1);
int secondLength = strlen(path_cmp2);
char *both = malloc(firstLength+secondLength+1);
memcpy(both, path_cmp1, firstLength);
memcpy(both+firstLength, path_cmp2, secondLength+1);
// this +1 copyes the second string's null-terminator too.
create a new string with the length of both inputs and strcpy/strcat the inputs and don't forget the null terminator.
Use strcat. (You are right that your code will lead to memory corruption.)
How about strcat in string.h?
path is just a pointer to path_cmp1 and you are trying to access beyond the end of the array. Very occasionally this will work, but in the vast majority of cases you will cause memory corruption.
As others have pointed out use strcat to concatenate strings.