String concatenation in c - c

I have a variable called char *inputstr, if the string length given to variable is a an odd number, I need to insert a "0" at the beginning of the string variable inputstr.
For example:
char *inputstr = "1ABc2" .
Now I need to append "0" and make it "01ABc2". How do I achieve this?
char a[2] = "0";
char *inputstr = "1ABc2";
if( strlen (inputstr) % 2 == 0)
{
strcat (a, inputstr);
strcpy (inputstr, a);
}
if( condition)
{
Using inputstr variable // here string value is along with junk characters
}

First, you need to set aside a buffer large enough for your target string:
/**
* Attempting to modify the contents of a string literal leads to undefined
* behavior; to be safe, pointers to literals should be declared "const".
* You are not going to write the modified string back to what inputstr
* points to.
*/
const char *inputstr = "1ABc2";
/**
* Compute the size of the target buffer, which is the length of inputstr
* plus 1 for the leading "0" plus 1 for the string terminator.
*/
size_t targetBufferLength = strlen( inputstr ) + 2;
/**
* Allocate the target buffer. Since targetBufferLength is a run-time
* value, this will only work with C99 and later. If you're using C90
* or earlier, targetBufferLength will have to be a compile-time constant,
* so you'll have to compute it manually and declare it as
*
* char targetBuffer[7]; // 5 + 1 + 1
*
* or
*
* #define TARGETBUFFERLENGTH 7
* ...
* char targetBuffer[TARGETBUFFERLENGTH];
*
*/
char target[targetBufferLength] = {0};
Now you can write your new string to the target buffer. You can use sprintf:
sprintf( target, "%s%s", "0", inputstr );
or you can use a combination of strcpy and strcat (or strncpy and strncat for the paranoid in the room):
strcpy( target, "0" );
strcat( target, inputstr );
Be aware of the potential for buffer overflow with either method. Make sure that your target buffer is large enough for the final string. Using strcpy and strcat is risky, but using strncpy and strncat in their place isn't a guarantee of success either.
You could also allocate the buffer dynamically:
char *target = calloc( targetBufferLength, sizeof *target );
The advantage of this is that you can resize the buffer as necessary if it
isn't big enough:
if ( strlen( target ) + strlen( newStr ) > targetBufferLength )
{
char *tmp = realloc( target, (targetBufferLength + strlen( newStr ) + 1) * sizeof *target );
if ( tmp )
{
target = tmp;
targetBufferLength += strlen( newStr ) + 1;
strcat( target, newStr );
}
else
{
// could not extend target buffer, don't append
}
}
The disadvantage is that you now have memory management issues, and you have to remember to free the buffer when you're done with it.

you can use memmove as the areas overlap but IMO is better to write a simple routine for it:
src - the string to append in front of the dest. dest has to be big enough to accommodate its new characters
char *straddfront(char *dest, const char *src)
{
size_t srclen = strlen(src);
size_t destlen = strlen(dest);
for (int i = 0; i <= destlen; i++)
*(dest + destlen + srclen - i) = *(dest + destlen - i);
strncpy(dest, src, srclen);
return dest;
}

You are searching for strcat (or really better strncat) defined in string.h
But you have to notice:
strcat concatenates two strings, thus you need to use the string "0" as the destination
if destination is not large enough, program behavior is unpredictable
the destination (the first argument of strcat i the only one that is modified, not the second argument (that is actually a const char*)

Related

C invalid operands to binary + (have ‘char *’ and ‘char *’)?

In C I have:
filedata->string_table + (X)->sh_name
Now I want to add the following string next to it: "new"
I tried:
filedata->string_table + (X)->sh_name + "new"
but this won't compile and I get:
readelf.c:6807:83: error: invalid operands to binary + (have ‘char *’ and ‘char *’)
filedata->string_table + (X)->sh_name : filedata->string_table + (X)->sh_name+"new")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
How to fix this?
Use proper way to concatenate strings.
If you want to add the result to existing buffer, use strcat() to concatenate strings.
char buffer[1024000]; /* enough size */
strcpy(buffer, filedata->string_table + (X)->sh_name);
strcat(buffer, "new");
You also can use snprintf() to put the result of concatenation in a buffer.
char buffer[1024000]; /* enough size */
snprintf(buffer, sizeof(buffer), "%s%s",
filedata->string_table + (X)->sh_name, "new");
To print the result to the standard output, use two %s format specifier to print the two strings in a row.
printf("%s%s",
filedata->string_table + (X)->sh_name, "new");
If the string "new" is fixed, also you can do like this:
printf("%snew",
filedata->string_table + (X)->sh_name);
You cannot concatenate strings or char using the operator +. Use strncat() or snprintf().
(X)->sh_name+"new" + in C does not concatenate the strings. It tries to add pointer to pointer which is invalid.
You need to use function strcat or strncat
Sorry These functions affect the strings but I want a new one –
it is so simple:
char *strcatAlloc(const char * restrict s1, const char * restrict s2)
{
size_t s1len;
char *newstring;
if(s1 && s2)
{
s1len = strlen(s1);
newstring = malloc(s1len + strlen(s2) + 1);
if(newstring)
{
strcpy(newstring, s1);
strcpy(newstring + s1len, s2);
}
}
return newstring;
}
int main(void)
{
// you should check if the function fails. Omitted for the example clarity
printf("`%s`\n", strcatAlloc("hello ", "world"));
printf("`%s`\n", strcatAlloc("", "world"));
printf("`%s`\n", strcatAlloc("hello ", ""));
printf("`%s`\n", strcatAlloc("", ""));
//you should free allocated space
}
or version where you can pass your buffer (it will allocate memory if that buffer is NULL)
char *strcatAlloc(const char * restrict s1, const char * restrict s2, char *buff)
{
size_t s1len;
if(s1 && s2)
{
s1len = strlen(s1);
if(!buff) buff = malloc(s1len + strlen(s2) + 1);
if(buff)
{
strcpy(buff, s1);
strcpy(buff + s1len, s2);
}
}
return buff;
}
int main(void)
{
char s[100];
// you should check if the function fails. Omitted for the example
printf("`%s`\n", strcatAlloc("hello ", "world", NULL));
printf("`%s`\n", strcatAlloc("", "world", NULL));
printf("`%s`\n", strcatAlloc("hello ", "", s)); //you can pass your own large enough buffer
printf("`%s`\n", strcatAlloc("", "", NULL));
//you should free allocaated space
}
Remember that C doesn't have an actual string type - strings are stored in arrays of char, and C doesn't define the + or = operators for array types.
You can append strings to a character buffer using strcat or strncat:
char foo[] = "This is ";
char bar[] = "a test";
char target[ sizeof foo + sizeof bar ];
strcpy( target, foo ); // copies contents of foo to target buffer
strcat( target, bar ); // appends contents of bar to target buffer
The target buffer must be large enough to accommodate the final string including the terminator. In this example, we took the sizes (not lengths!) of foo and bar which are 9 and 7 respectively (including the string terminators). Note that this would not work if they were declared as
char *foo = "This is ";
char *bar = "a test";
because sizeof foo would only give us the size of the pointer object, not the size of the string to which it points. In that case you'd have to get the size at runtime using strlen. If you're using a version that supports VLAs (C99 or later), you could simply do
char *foo = "This is ";
char *bar = "a test";
char target[ strlen( foo ) + strlen( bar ) + 1];
If not, you'd have to allocate your buffer dynamically:
char *target = malloc( strlen( foo ) + strlen( bar ) + 1 );
and you'd have to remember to free it when you're done.
If you have a mix of string and non-string types, you can use sprintf:
char *name = "blah";
int number = 42;
sprintf( target, "%s-%d", name, number ); // writes "blah-42" to target buffer
Again, the target buffer must be large enough to store the resulting string plus the terminator.

How to append a char at a defined position

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

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

Is there a better way to write this function?

Here is a insert string function,
void ins( char * T, size_t ip, char * P)
{
char temp1[100], temp2[100];
strncpy(temp1,T,ip);
strcpy(temp2, &T[ip]);
strcat(&T[ip], P);
strcat(&T[sizeof(temp1) + sizeof(P) - 2], temp2);
}
Is there a better way to write this function?
I needed to add an extra argument maxlen: the maximal size of str that can be written to. I also modified the return type to something useful.
size_t do_insert(char *str, size_t maxlen, size_t where, char *ins)
{
size_t len_str, len_ins;
/* these could be arguments, too,
** if these are already known by the caller.
*/
len_str = strlen(str);
len_ins = strlen(ins);
/* not enough space: return */
if (len_str + len_ins >= maxlen)
return len_str + len_ins;
/* I don't know what should happen if the place to insert
** is beyond the length of str
** [ there also is a corner case lurking here if where == len_str]
*/
if (where > len_str)
return ???;
/* make place for the insert by shifting str up.
** we move one byte extra: the nul character.
*/
memmove( str + where + len_ins, str + where, len_ins + 1);
/* put the insert where it belongs */
memcpy ( str + where, ins, len_ins );
/* return the length of the new string */
return len_str + len_ins;
}
NOTE: Untested.

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