How to append a char at a defined position - c

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);

Related

string replace using dynamically allocated memory

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.

Seg fault error?

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.

Trying to remove a char from a string using pointers

I am trying to figure out a way to remove a char from a string based on an index value using pointers and not touching array notation (by which I essentially mean not using any brackets) at all. As far as I understand *letter = temp should assign what is in temp into the location of letter, but it creates a segmentation fault instead.
char *word = "blue";
int length = strlen(word);
int index = 0;
for (index; index < length; index++)
{
char *letter = word + index;
char temp;
temp = *(letter + 1);
*letter = temp;
}
printf("%s\n", word);
Edit: Bolded something that the answers seem to be ignoring.
I've put my comments in the code about what is going on
/* normally we would do char word[] = "blue" but that isn't allowed
* We need to put it on the heap where it can be modified but
* we can't use array indexing [] so we can do the hack
* below */
/* String constants are immutable - they can't be changed
* so consider them read only. Trying to modify one can
* lead to undefined behavior including write fault */
char *constWord = "blue";
int index = 0;
int length = strlen(constWord);
/* Create space on the heap to hold the string + nul terminator */
char *word = malloc(strlen(constWord + 1));
/* Copy the string to the heap where it can be modified */
strcpy(word, constWord);
for (index; index < length; index++) {
char *letter = word + index;
char temp;
temp = *(letter + 1);
*letter = temp;
}
printf("%s\n", word);
/* Cleanup */
free(word);
}
word is a pointer which is initialized to point to a string constant. The pointer word may be modified to point to another string, however if you attempt to modify the string at which word is pointing the result is undefined.
Instead you can do char word[] = "blue". Here word is an array big enough to hold a word and \0 following the word. Individual characters within the array can be changed however the address of the array will remain same.

What's wrong with this character buffer code?

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;
}

How to Concatenate 2 C strings, without overwriting any terminating Null characters?

I am trying to set up a list of file names for a parameter to SHFileOperation. I want to be able to concatenate a file name onto the char array, but i dont want to get rid of the terminating character. for example, I want this:
C:\...\0E:\...\0F:\...\0\0
when i use strcat(), it overwrites the null, so it looks like
C:\...E:\...F:\...0\
Is there any easy way to do this? or am i going to have to code a new strcat for myself?
The code is pretty straightforward. Use a helper pointer to track where the next string should start. To update the tracker pointer, increment by the length of the string +1:
const char *data[] = { "a", "b", "c" };
size_t data_count = sizeof(data) / sizeof(*data);
size_t d;
size_t buffer_size;
char *buffer;
char *next;
// calculate the size of the buffer
for (d = 0; d < data_count; ++d)
buffer_size += (strlen(data[d] + 1);
buffer_size += 1;
buffer = malloc(buffer_size);
// Next will track where we write the next string
next = buffer;
for (d = 0; d < data_count; ++d)
{
strcpy(next, data[d]);
// Update next to point to the first character after the terminating NUL
next += strlen(data[d]) + 1;
}
*next = '\0';
Use memcpy.
memcpy(dest, src1, strlen(src1)+1);
memcpy(&dest[strlen(src1)+1], src2, strlen(src2)+1);
Using the GNU stpcpy() may be slightly more elegant, if you know beforehand the maximum 'length' of the resulting char array.
char *src[] = {"C:\\foo", "E:\\bar", "F:\\foobar", 0};
char dst[MY_MAX_LEN], *p = dst;
int i;
for (i = 0; src[i]; i++)
p = stpcpy(p, src) + 1;
*p = 0;
assert(p < dst + sizeof dst);
If needed, stpcpy() can be defined as:
char *stpcpy(char * restrict dst, const char * restrict src)
{
return strcpy(dst, src) + strlen(src);
}
just use strcat to append to the original string, but add one to the offset so you're bypassing the previous string's 0 terminator.
// an example
char testString [256];
strcpy (testString, "Test1");
strcat (testString + strlen(testString)+1, "Test2");
strcat (testString + strlen(testString)+1, "Test3");
testString will now contain "Test1\0Test2\0Test3\0"

Resources