Does anyone know why I keep getting this seg fault error?
I am trying to run a program that locates a substring "from" within "src" and replaces all non-overlapping occurrences of "from" in src with "to" in the output string "dest".
Also, could anyone provide me with the proper way to test this case? As I'm not too sure how I could display this with type "void"... (Trying this as an exercise)
void find_replace(char* src, char* from, char* to, char* dest)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
dest[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
dest[i + (count * diff)] = src[i];
}
}
return ;
}
Is it sufficient enough to do this for a test?
int main (int argc, char *argv[])
{
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)" dest);
for (int i = 0; i < strlen(dest); i++)
{
printf("%c", dest[i]);
}
printf("\n");
}
The problems happens because you are trying to access an unallocated pointer with
strlen(dest)
In the for in your main program.
The reason for this is that you sent the value of the pointer dest to the function, not the pointer itself, so when you allocated the memory inside your function, so you didn't actually modify the memory address stored in the pointer outside of it.
When you send the pointer as a parameter of a function, what you are actually doing is sending the memory address stored in that pointer, you are sending the value stored in the pointer, not the pointer itself.
If you want to get the allocated memory address for the string, you either can make the function return it, or you can declare and send dest as a pointer to a pointer.
EDIT: As the other comment points out, you can also perform the allocation in main(), instead of doing it inside your function.
A few minor tweaks to your program is all you need.
Change the return value of find_replace to be the newly allocated memory for the changed string.
Instead of
void find_replace(char* src, char* from, char* to, char* dest)
Use
char* find_replace(char* src, char* from, char* to)
Change the implementation slightly.
Instead of
dest = malloc(destlength);
use
char* dest = malloc(destlength);
and
Instead of
return;
use
return dest;
Change the way you use the function.
Instead of
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest);
use
char* dest = find_replace("hello my name is leeho lim", "leeho lim", "(insert name)");
Make sure to deallocate memory returned by find_replace.
free(dest);
Here's a fully working program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* find_replace(char* src, char* from, char* to)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
char* dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
dest[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
dest[i + (count * diff)] = src[i];
}
}
return dest;
}
int main (int argc, char *argv[])
{
char* dest = find_replace("hello my name is leeho lim", "leeho lim", "r sahu");
for (int i = 0; i < strlen(dest); i++)
{
printf("%c", dest[i]);
}
free(dest);
printf("\n");
}
Update, in response to OP's comment
If the return type of find_replace must be void, there are couple of options on how to deal with the memory needed for dest.
Allocate memory for dest in the calling function.
char* dest = malloc(SUFFICIENT_SIZE);
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest);
free(dest);
Then, there is no need for the line
dest = malloc(...);
in find_replace.
Allocate memory for dest in find_replace. Then, you need to pass a pointer to a pointer.
void find_replace(char* src, char* from, char* to, char** dest)
and use *dest instead of just dest in the function.
void find_replace(char* src, char* from, char* to, char** dest)
{
int count = 0;
int diff = strlen(to) - strlen(from);
int destlength = strlen(src);
*dest = malloc(destlength);
for (int i = 0; i < strlen(src); i++)
{
int index = 0;
while (src[i+index] == from[index] && index < strlen(from)){
index++;
}
if (index == strlen(from)) {
for (int j = 0; j < strlen(to); j++) {
(*dest)[i+j+(count * diff)] = to[j];
}
i += strlen(from) - 1;
count++;
}
else {
(*dest)[i + (count * diff)] = src[i];
}
}
return;
}
and change the you call find_replace.
char* dest;
find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", &dest);
There are two main problems with your (original) code:
it does not provide for your find_replace() function to return the allocated destination buffer to the caller, and
it does not reliably allocate enough space for the destination buffer.
In principle, issue (1) could be resolved in two ways. Either the space could be allocated by the caller and a pointer to it passed to the function, or the space could be allocated by the function and a pointer returned to the caller. Your original code allocates space in the function, but does not return a pointer to it to the caller.
It is preferable for the function to perform the allocation, because satisfying issue (2) requires a more thorough analysis of the inputs than makes sense to insist the caller perform. Consider what happens in your revised code when you do this:
char dest[4];
int canary = 0;
find_replace("aaa", "a", "longer string", dest);
assert(canary == 0);
Most likely you get a segfault, possibly you get an assertion failure, and perhaps you get who-knows-what, because find_replace() cannot perform its job without writing past the end of dest, the result of which is undefined.
Although you've said the exercise requires your function to have no return value (i.e. void), it can still return a pointer to the destination string via the argument list. You simply pass a pointer to the dest pointer instead of its value, so that the function can update that value. The signature would look like this:
void find_replace(const char *src, const char *from, const char *to,
char **dest_p);
(Note the const qualifers for src, from, and to, which are appropriate, if not necessary, if the function is meant to accept string literals.)
The amount of space needed for dest is the length of src plus one for the terminator plus, if to is longer than from, the difference between the lengths of the to and from strings times the number of appearances of the to string. You could, however, compute an upper bound on that length, and later shrink the allocation (if needed) after you find out how much space is actually used. For example:
void find_replace(const char *src, const char *from, const char *to,
char **dest_p) {
ssize_t src_size = strlen(src);
ssize_t from_size = strlen(from);
ssize_t to_size = strlen(to);
char *temp;
if (!from_size) {
/* special case: the 'from' string is empty ... */
/* whatever you do, set temp to something valid or NULL */
} else {
ssize_t size_diff = to_size - from_size;
if (size_diff < 0) size_diff = 0;
temp = malloc(1 + src_size + (src_size / from_size) * size_diff);
if (temp) {
/* use next to track the next unused position in temp */
char *next = temp;
/*
* perform the substitution, updating 'next' appropriately as
* you go along (INSERT CODE AFTER THIS COMMENT) ...
*/
/* be sure to terminate: */
*(next++) = '\0';
/* shrink the string to the actual space used (optional): */
next = realloc(temp, next - temp);
/*
* On (re)allocation error, next will be NULL and temp will still
* be a valid pointer. Otherwise, next will be a pointer to the
* space, not necessarily equal to temp, and temp might no longer
* be a valid pointer.
*
* An OK error recovery strategy is to just return a pointer
* to the full-size space.
*/
if (next) {
temp = next;
}
} /* else allocation failure; return NULL */
}
/*
* The caller gets a pointer to the allocated space (if any). It is his
* responsibility to free it when it is no longer needed.
*/
*dest = temp;
}
The actual substitution code is left as an exercise, since this is homework, after all.
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);
I'm trying to create a function that takes two input strings, dest and src, and appends the src string to the dest string.
Below is the current function I have. However, when I try to use it, I
get an error stating "returning 'char' from a function without a cast." I understand that my error involves the return statement and how I'm using it as a pointer, but I'm unsure how to fix it.
char* strcat(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char result[destL + srcL];
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return *result;
}
The lenstr function is:
int lenstr(char* s) {
int len = 0;
while(s[len++] != '\0');
return len-1;
}
You cannot return a locally declared array. Well you can, but the data may be overwritten at any time since it is no longer valid.
What you need to do is something like this:
char* strcat(char dest[], char src[]) {
char * result = malloc((lenstr(dest)+lenstr(src)+1) * sizeof *result);
// Code to copy data
return result;
}
Note that +1 is important to make room for the \0 terminator.
However, when I try to use it, I get an error stating "returning 'char' from a function without a cast."
This error simply indicates that your return value doesn't match the function declaration. In your function declaration, you have mentioned that it returns a char *. However, in your actual return statement, you are returning *result which is a dereferenced char pointer i.e. a char.
The second problem in your code is that you are returning an array from the function. Memory allocated using an array in a method becomes unavailable to the caller method. You need to create memory on heap and return a pointer to it and then let the caller free up the memory after usage.
Checkout the following working code:
char* strcat1(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char * result = malloc(sizeof(char) * (destL + srcL));
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return result;
}
Please make sure the caller frees up the result as shown below:
char * result = strcat1("hi", "ho");
printf(result);
free(result);
I am using the below function to replace a sub-string in a given string
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
The problem with the above function is memory leak. Whatever memory is allocated for inputString will be lost after this line.
*inputString = result;
since I am using strstr and moving pointer of inputString *inputString += fromlen; inputString is pointing to NULL before the above line. So how to handle memory leak here.
Note: I dont want to return the new memory allocated inside the function. I need to alter the inputString memory based on new length.
You should use a local variable to iterate over the input string and avoid modifying *inputString before the final step where you free the previous string and replace it with the newly allocated pointer.
With the current API, ReplaceSubStr must be called with the address of a pointer to a block allocated with malloc() or similar. Passing a pointer to local storage or a string literal will have undefined behavior.
Here are a few ideas for improvement:
you could return the new string and leave it to the caller to free the previous one. In this case, you would take the input string by value instead of by address:
char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
If the from string is empty, you should either insert the to string between each character of the input string or do nothing. As posted, your code has undefined behavior for this border case.
To check if the from string is present at offset i, use memcmp instead of strstr.
If cnt is 0, there is nothing to do.
You should return an error status for the caller to determine if memory could be allocated or not.
There is no need to initialize the result array.
avoid using strncpy(). This function has counter-intuitive semantics and is very often misused. Read this: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
You cannot obviously free the input as it can be a literal, some memory you don't control. That would cripple your function even more than now.
You could return the old value of inputString so you'd be able to free it if needed.
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
The caller is responsible to free the contents of old_string if needed.
If not needed (we have to workaround the char ** input by assigning a valid writable array to a pointer to be able to pass this pointer:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
if needed:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
or just
free(ReplaceSubStr(&input, "hello", "hi"));
then always (when replaced string isn't needed):
free(input);
The only constraint is that you cannot use a constant string literal as input (const char *input = "hello world") because of the prototype & the possible return of a char * to pass to free.
I try to code my own concatenation function in C without library, but I have issue and I don't know where it comes from.
To do my function I use pointers of char.
This is my Code :
#include <stdio.h>
#include <stdlib.h>
int longueur(char *str)
{
int i =0;
while(str[i] != '\0')
{
i++;
}
return i;
}
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = dest;
free(dest);
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
while(temp[i] != '\0')
{
dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
int main()
{
char *str1 = "World";
char *str2 = "Hello";
concat(str1, str2);
printf("-------------\n%s", str2);
return 0;
}
EDIT
I read all your answer, so I changed my concat function to :
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
dest = (char*) malloc((longStr1 + longStr2)* sizeof(char) + sizeof(char));
while(dest[i] != '\0')
{
dest[i] = dest[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
Now I don't have issue but my code only display "Hello"
In addition to all the good comments and solutions: realloc can give you a different pointer and you must return that pointer. So your function signature should be:
void concat(char* source, char** dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = *dest, *temp2;
if ((temp2 = realloc(dest, ((longStr1 + longStr2)+1))==NULL) return;
*dest= temp2;
while(temp[i] != '\0')
{
*dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
*dest[i] = source[j];
i++;
j++;
}
*dest[i] = '\0';
}
..and this assumes the function will only be called with a dest that was allocated with malloc. And sizeof(char) is always 1. (This resulting function is not optimal.)
--EDIT--
Below the correct, optimized version:
void concat(char* source, char** dest)
{
int longSrc = longueur(source);
int longDst = longueur(dest);
char *pDst, *pSrc;
if ((pDst = realloc(*dest, longSrc + longDst + 1))==NULL) return;
if (pDst != *dest) *dest= pDst;
pDst += longSrc;
pSrc= source;
while(pSrc)
*pDst++ = *pSrc++;
*pDst = '\0';
}
In your code
free(dest);
and
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
invokes undefined behavior as none of them use a pointer previously allocated by malloc() or family.
Mostly aligned with your approach, you need to make use of another pointer, allocate dynamic memory and return that pointer. Do not try to alter the pointers received as parameters as you've passed string literals.
That said, you need to have some basic concepts clear first.
You need not free() a memory unless it is allocated through malloc() family.
You need to have a char extra allocated to hold the terminating null.
Please see this discussion on why not to cast the return value of malloc() and family in C..
If your concatenation function allocates memory, then, the caller needs to take care of free()-ing the memory, otherwise it will result in memory leak.
After you have freed dest here:
free(dest);
You cannot use this pointer in following call to realloc:
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
man realloc
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block
pointed to by ptr to size bytes. (...)
But this pointer is invalid now and you cannot use it anymore. When you call free(dest), the memory dest points to is being freed, but the value of dest stays untouched, making the dest a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
NOTE:
Even if free(dest) is technically valid when called on pointer to memory allocated by malloc (it is not an error in your function to call free(dest) then), it is incorrect to use this on pointer to literal string as you do in your example (because str2 points to string literal it is an error to pass this pointer to function calling free on it).
Given your original use, perhaps you would find a variant like this useful
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t longueur ( const char * str ) { /* correct type for string lengths */
size_t len = 0;
while (*str++ != '\0') ++len;
return len;
}
char * concat ( const char * first, const char * second ) {
const char * s1 = first ? first : ""; /* allow NULL input(s) to be */
const char * s2 = second ? second : ""; /* treated as empty strings */
size_t ls1 = longueur(s1);
size_t ls2 = longueur(s2);
char * result = malloc( ls1 + ls2 + 1 ); /* +1 for NUL at the end */
char * dst = result;
if (dst != NULL) {
while ((*dst = *s1++) != '\0') ++dst; /* copy s1\0 */
while ((*dst = *s2++) != '\0') ++dst; /* copy s2\0 starting on s1's \0 */
}
return result;
}
int main ( void ) {
const char *str1 = "Hello";
const char *str2 = " World";
char * greeting = concat(str1, str2);
printf("-------------\n%s\n-------------\n", greeting);
free(greeting);
return 0;
}
In this variant, the two inputs are concatenated and the result of the concatenation is returned. The two inputs are left untouched.
I'm trying to program a function that allows me to locate a substring "from" in a string "src", and replace the "from" substring with the "to" substring in all cases, and output the new string through "dest"; however I think my code looks a bit iffy, and I do not understand (conceptually) how I would return an output with dest, given that the output is of type void. I was wondering if someone could offer some assistance?
for example:
find_replace("pooppoop poop", "poo", "hel", dest) should return
"helphelp help"
thank you!
void find_replace(char* src, char* from, char* to, char* dest)
{
dest = (char * ) malloc(sizeof(src)+sizeof(from));
int i;
int j;
int check = 1;
for (i = 0; i <= strlen(src) - 1; i++) {
if (src[i] == from[0]) {
for (j = 0; j <= strlen(from) - 1; i++) {
if (src[i+j] != from[j]) {
check = 0;}
else {
continue;
}}}
if (check == 1) {
char * str3 = (char *) malloc(1 + strlen(&src[i]) + strlen(to));
strcpy(str3, &src[i]);
strcat(str3, to);
}
else { continue; }
}
return ;
You allocate memory for a new string in your example, but the calling code cannot acces this variable.
Basically, there are three methods to pass a string. Each has advantages and drawbacks.
Pass a fixed-size buffer
int repl1(char *dest, int n, const char *src, const char *find, const char *repl)
Here, the calling function provides a buffer to which the function can write. It is a good idea to provide a maximum buffer length, so that the function does not overflow that buffer. The arguments, whose contents you don't intend to change should be const, i.e. pointers to unmodifiable data.
Such a function can be void, but it could also return an integer that indicates how long the string in dest is.
The advantage is that you can easily pass automatic buffers. The disadvantage ist that these buffers might be too small for the task.
Call the function like this:
char buf[80];
int n = repl1(buf, sizeof(buf), str, "this", "that");
Return allocated memory
char *repl2(const char *src, const char *find, const char *repl)
Here, the function should allocate new memory to hold the buffer. The function returns the pointer to the new memory. That memory "belongs" to the calling function, which then is responsible for freeing the memory.
The advantage is that the function can allocate enough memory for the task. The disadvantage is that the calling function must take care of managing the new memory.
Call the function like this:
char *dest = repl2(str, "this", "that");
// Do stuff whith 'dest' ...
free(dest);
Pass a pointer to a poiner to char
int repl3(char **dest, const char *src, const char *find, const char *repl)
This is a variant of returning the pointer, where the pointer is passed by reference and can therefore be changed. The function also has access to the old contents to the dest char buffer. That is not useful in your case. I have only mentioned this possibility for completeness.
Call the function like this:
char *buf;
int n = repl3(&buf, str, "this", "that");
This answer addresses the ways of passing data. Your code uses the second method, so you should return dest, but not pass it in as parameter. I have not looked at your function logic.
Void type method won't return anything, what you can do is change the type of your function to string and return a string.
Void means nothing, so you can't return a value with a void function.
I assume you want to use call-by-reference instead of call-by-value, if you want to use a void function.
This means, that you give a pointer to the function, to tell where your array is located. Then you work with your 'real' array, instead of a copy.
[Apart from analyzing the logic of your function] A function with a return type void won't [and can't] return any value using the return statement. Also, worthy to mention, you cannot return more than one value [as you need] using a return statement, either.
To get the return value(s) in your case, you're supposed to call your function and pass pointer(s) to char as argument. Then, inside your function, when you assign/alter values of the locations pointed by those pointers, they will get modified and after returning from your function, in the caller function, you'll have the modified value.
This is another way to have more than one return value at a time from a called function.
printf("%s\n",find_replace("pooppoop poop", "poo", "hel", dest));
char * find_replace(char* src, char* from, char* to, char* dest)
{
dest = (char * ) malloc(sizeof(src)+sizeof(from));
int i;
int j;
int check = 1;
for (i = 0; i <= strlen(src) - 1; i++) {
if (src[i] == from[0]) {
for (j = 0; j <= strlen(from) - 1; i++) {
if (src[i+j] != from[j]) {
check = 0;}
else {
continue;
}}}
if (check == 1) {
char * str3 = (char *) malloc(1 + strlen(&src[i]) + strlen(to));
strcpy(str3, &src[i]);
strcat(str3, to);
return str3 ;
}
else { continue; }
}
return "";
}
The line:
dest = (char * ) malloc(sizeof(src)+sizeof(from));
overrides the address passed in
void find_replace(char* src, char* from, char* to, char* dest)
If you want to allocate memory inside the function (which I think you have to, because the caller cannot know how much to reserve), you have to tell the caller where the result data ends up in. Either you opt for an out-parameter:
void find_replace(char* src, char* from, char* to, char** dest)
{
*dest = malloc(...);
or, what I would prefer, you return the pointer:
char* find_replace(char* src, char* from, char* to)
{
char* dest = malloc(...);
// ...
return dest;
}