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

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"

Related

Changing size of dynamic *char

Is there way how to make my string to even size?
EDIT:
I need a few string in struct that have even length. So something like:
struct msg { char * first; char * second; char * third; };
so it is in the end something like first string "hi\0\0" second string "hello\0" third string "byebye\0\0" and i need to change them anytime+they are dynamic allocated.
Create a strdup_even().
Allocate memory as needed to copy the string, plus maybe 1 more to make "even".
char *strdup_even(const char *str) {
size_t len = strlen(str) + 1; // Size needed for the _string_
size_t len2 = len + len % 2; // Even allocation size
char *copy = malloc(len2);
if (copy) {
memcpy(copy, str, len);
if (len2 > len) {
copy[len] = '\0';
}
}
return copy;
}
Sample usage
struct msg m;
m.first = strdup_even("hi");
m.second = strdup_even("hello");
Use malloc() and realloc():
char *string = malloc(STRING_SIZE);
strcpy(string, "hi");
string = realloc(string, STRING_SIZE+1);
string[STRING_SIZE] = '\0';

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

How can I predetermine the size of a malloc to concatenate an array of strings?

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

Convert *char or char to bits

How do I convert * char or char to bits ?
For example:
Here 's my declarations
uint64_t blocks[64];
char * word = "hello";
How do I store the word hello in bytes inside blocks[0] ?
I tried this
int e;
int a = strlen(word);
for (e = 0; e < a; e++) {
blocks[0] |= !!word[e] >> 8;
}
Also, how will I reverse the process?
"I want to copy the bits in a char into a uint64_t."
Try using memcpy:
void * memcpy(void * dst, const void * src, size_t n)
e.g.
memcpy(blocks, word, strlen(word));
More than one string
Regarding your comment which I interpret to be about copying more than one string:
memcpy copies n bytes from src to dst, so if we want to copy several strings in succession, we need to make sure calls to memcpy have src set to the end of the last string we copied, assuming we want to copy "hello" and then "world" into blocks and end up with the bytes that represent "helloworld".
// if you have a char** words and uint64_t blocks[64]; or similar
uint64_t blocks[64];
const char *words[2] = { "hello", "world" };
size_t offset = 0, len;
int num_words = sizeof words / sizeof words[0], n;
for (n = 0; n < num_words && offset < sizeof blocks; ++n) {
len = strlen(words[n]);
memcpy(((void *)blocks) + offset, words[n], len); // note the void * cast
offset += len;
}
This should be easily adaptable to a situation where you are reading in the strings rather than having an array of array of chars.
Getting a string back again
To take blocks and get a char * with all the bytes in it, we need to remember that strings in C are null terminated, so if we want to treat the result as a string, it needs a null on the end. The last offset you have once you are done copying (from above) could be used to add this.
char new_word[100];
memcpy(new_word, blocks, sizeof new_word);
new_word[offset] = 0;
We don't have to copy the data to treat this as a char *, by the way; We could just cast...
char * new_word = (char *)blocks;
...but remember that if you do this, modifying new_word will also modify blocks.

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

Resources