What is a safe way to join strings in C? - c

I need to construct a path to a file from two strings. I could use this (not tested, though):
/* DON'T USE THIS CODE! */
/* cmp means component */
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
unsigned len = strlen(path_cmp1);
char *path = path_cmp1;
for (int i = 0; i < strlen(path_cmp2); i++) {
path[len + i] = path_cmp2[i];
}
but this could lead to memory corruption I guess. Is there a better way to do this, or is there a function for this in the standard library?

#include <stdlib.h>
#include <string.h>
char *join(const char* s1, const char* s2)
{
char* result = malloc(strlen(s1) + strlen(s2) + 1);
if (result) // thanks #pmg
{
strcpy(result, s1);
strcat(result, s2);
}
return result;
}
This is simple enough to be written in place, especially when you have multiple strings to concatenate.
Note that these functions return their destination argument, so you can write
char* result = malloc(strlen(s1) + strlen(s2) + 1);
assert(result);
strcat(strcpy(result, s1), s2);
but this is less readable.

#include <stdio.h>
char *a = "hello ";
char *b = "goodbye";
char *joined;
asprintf(&joined, "%s%s", a, b)

There are several problems in this code:
1 - calling strlen on the for loop is a bad idea, it will calculate the string length every iteration, so it is better to call it once before the loop and keep the result in a variable.
2 - The same strlen problem applies to strlen(path_cmp1) inside the loop, call it before the loop and increments its size.
In the end, it is better to simple copy both strings and store those on a dynamic allocated string, like:
char *join_strings(const char* s1, const char* s2)
{
size_t lens1 = strlen(s1);
size_t lens2 = strlen(s2);
//plus 1 for \0
char *result = malloc(lens1 + lens2 + 1);
if(result)
{
memcpy(result, s1, lens1);
memcpy(result+lens1, s2, lens2+1);
}
//do not forget to call free when do not need it anymore
return result;
}

There are strcat and strncat for that.

char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
int firstLength = strlen(path_cmp1);
int secondLength = strlen(path_cmp2);
char *both = malloc(firstLength+secondLength+1);
memcpy(both, path_cmp1, firstLength);
memcpy(both+firstLength, path_cmp2, secondLength+1);
// this +1 copyes the second string's null-terminator too.

create a new string with the length of both inputs and strcpy/strcat the inputs and don't forget the null terminator.

Use strcat. (You are right that your code will lead to memory corruption.)

How about strcat in string.h?

path is just a pointer to path_cmp1 and you are trying to access beyond the end of the array. Very occasionally this will work, but in the vast majority of cases you will cause memory corruption.
As others have pointed out use strcat to concatenate strings.

Related

How to remove a single character from the beginning of a character array? [duplicate]

I have a string:
str1 = "abcabcabc";
How can I remove the first character? I would like the end result to be:
str1 = "bcabcabc";
If you have a character pointer to a string like:
char *s = "This is my string";
then you can just do s++.
If you have a character array, your best bet may be to have a pointer to that array as well:
char s[] = "This is my string";
char *ps = s;
then you can do ps++ and make sure you use ps rather than s.
If you don't want to have a separate pointer to your array then you can use memmove to copy the data:
memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)
though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.
Another solution is to simply code up a loop:
for (char *ps = s; *ps != '\0'; ps++)
*ps = *(ps+1);
*ps = '\0';
This will work for all strings, empty or otherwise.
Pointer tricks (zero-cost):
char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"
Or:
char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"
In-place via memmove:
char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"
Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.
Into a new string via strcpy:
char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"
Into a new string via C++'s std::string::substr:
std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"
Into a new string via C++'s std::copy:
std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"
There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)
If you really meant to say
char str1 [] = "abcabcabc";
Then the easiest thing is
str1 = &str1[1];
If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.
If you really meant C++ and you're using the string object then you can use
str1 = str1.substr(1);
Here is one way to do it:
int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer.
The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.
#include <stdio.h>
#include <conio.h>
main(){
char a[10];
int i;
gets(a);
for (i = 0; a[i] != '\0'; i++) {
a[i] = a[i + 1];
}
printf("\n");
puts(a);
getch();
}
#include <stdio.h>
int main() {
char a[15] = "!Hello world!";
sprintf(a,"%s",a+1);
printf("%s",a);
}

Trying to troubleshoot concatenating a string in C

I am trying to concatenate two strings together. I put two strings into two arrays and created a third array that is the size of the two strings. Then I use the for loop to print out one letter at a time.
The program gets to This before crashing. There are no error codes or debug messages in the IDE!!! How do I debug my program and what kind of mindset should I have if I have no obvious error messages to go off of when something like this happens?
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
int pointerArrays() {
char strOne[] = {"This is the first string array."};
char strTwo[] = {"This is the second string array."};
char *px, *py, *pz;
px = strOne;
py = strTwo;
pz = (char *) malloc(1 + sizeof(px) + sizeof(py));
strcpy(pz, px);
strcpy(pz, py);
for (int i = 0; i < sizeof(pz); i++) {
printf("%c", pz[i]);
}
return 0;
}
int main(void) {
pointerArrays();
return 0;
}
There are two problems. First of all, this here doesn't work:
malloc(1 + sizeof(px) + sizeof(py));
sizeof(px) doesn't evaluate to the size of the string, it just evaluates to the size of a char*, which isn't what you intended. Instead, try something like this:
pz = (char *)malloc(strlen(strOne) + strlen(strTwo) + 1);
The second problem is that instead of concatenating the two strings, you're copying them over each other. The second call needs to be
strcat(pz, py);
Rather than strcpy again.
On a side note, when you print a string, instead of just looping through the array, you can also just use the %s format specifier:
printf("%s", pz);
Last but not least, don't forget to free the memory when you're done:
free(pz);
Insert another line to see what the argument to malloc() rceives:
printf ("malloc(%d)\n", 1 + sizeof(px) + sizeof(py));
I bet you can figure it out from there.
Just a sidenote (not the reason of your crash): you are copying to the same location twice:
strcpy(pz, px);
strcpy(pz, py);
should be
strcpy(pz, px);
strcpy(pz + strlen(px), py);
not fixing it would cause y to right OVER x
But the main issue is using sizeof instead of strlen. sizeof will return the pointer's size (4 or 8 typically), while strlen will actually return the length of the string (which is what you expected)
using sizeof is very dangerous and will fail in most real life usage cases.
it is enough to change
char strOne[] = "This is the first string array.";
char strTwo[] = "This is the second string array.";
to
char strOne[64] = "This is the first string array.";
char strTwo[64] = "This is the second string array.";
or
char *strOne = "This is the first string array.";
char *strTwo = "This is the second string array.";
and the result of your function will be far from the expected.
Always use strlen to get the string length.
Here you have much more universal and safer solution:
char *concatenate(const char *str1, const char *str2)
{
size_t str1len = strlen(str1), str2len = strlen(str2);
char *res = malloc(str1len + str2len + 1);
if(res)
{
strcpy(res, str1);
strcpy(res + str1len, str2);
}
return res;
}

Getting a heap error when trying to free

This smells like a heap corruption of some kind but I can not seem to find it.
the problem occurs on string_utils_replace() when trying to run free(tmp_for_free). the function is supposed to replace every occurrence of "search" with "replace" in "string".
char* string_utils_part_of_string(char *string, int from, int to)
{
int size_to_allocate = to - from + 1;
char *result = (char*)malloc(sizeof(char) * size_to_allocate);
strncpy(result, string + from, to - from);
result[size_to_allocate - 1] = '\0';
return result;
}
char* string_utils_replace(char *search, char *replace, char *string)
{
char *end, *result = string, *tmp_for_free = NULL;
int before_replace, after_replace;
int size_search = strlen(search);
int size_replace = strlen(replace);
int size_string, size_find;
int first_time = 1;
char *find = strstr(string, search);
if (find == NULL)
return string_utils_copy_string(string);
while (find != NULL)
{
tmp_for_free = result;
size_string = strlen(result);
size_find = strlen(find);
before_replace = size_string - size_find;
after_replace = before_replace + size_replace;
end = string_utils_part_of_string(result, after_replace, size_string);
result = string_utils_part_of_string(result, 0, before_replace);
strcat(result, replace);
strcat(result, end);
// no memory leaks, hooray!
free(end);
if (first_time == 0)
free(tmp_for_free);
size_string = strlen(result);
find = strstr(result, search);
first_time = 0;
}
return result;
}
any ideas?
As per the man page of strcat(),
char *strcat(char *dest, const char *src);
[..] and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable;
In your string_utils_part_of_string() function, you did not allocate enough memory to the result to be able to hold the entire input, and later, you're trying to use the same pointer to store the whole input, through strcat(). This is creating the memory overrun which in turn invokes undefined behaviour.
Note: Please do not cast the return value of malloc() and family in C.
You are causing a buffer overflow here:
result = string_utils_part_of_string(result, 0, before_replace);
strcat(result, replace);
strcat(result, end);
result is allocated exactly before_replace+1 bytes and initialized with before_replace bytes from the beginning of string and a final '\0'. You cannot concatenate replace and end to this array, it is full already.
The logic in your function is convoluted. You should simplify it. For instance, you should first run a loop counting the number of occurrences of find in string, then allocate a buffer for the result, then run a second loop copying fragments of string and copies of replace.
You should also test if find is an empty string. strstr() will always find the empty string, causing your algorithm to loop endlessly.

Parsing a string with multi-char delimiter and got junk data along with the result in the second call in c

I have writen a code to split the string with multiple char delimiter.
It is working fine for first time of calling to this function
but i calling it second time it retuns the correct word with some unwanted symbol.
I think this problem occurs because of not clearing the buffer.I have tried a lot but cant solve this. please help me to solve this problem.
char **split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist= malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
arraylist[i]=malloc(sizeof(buf));
arraylist[i]=buf;
i++;
loc = loc+length;
loc1 = loc;
}
return arraylist;
}
called this function first time
char **splitdetails = split("100000000<delimit>0<delimit>hellooo" , "<delimit>");
It gives
splitdetails[0]=100000000
splitdetails[1]=0
splitdetails[2]=hellooo
but i called this second time
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
splitdetails[0]=20000000��������������������������
splitdetails[1]=10����
splitdetails[2]=testing
Update:-
thanks to #fatelerror. i have change my code as
char** split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist = malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(strlen(loc1) + 1);
strcpy(arraylist[i], loc1);
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
buf[loc - loc1] = '\0';
arraylist[i]=malloc(strlen(buf));
strcpy(arraylist[i], buf);
i++;
loc = loc+length;
loc1 = loc;
}
}
In the caller function, i used it as
char *id
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
id = splitdetails[0];
//some works done with id
//free the split details with this code.
for(int i=0;i<3;i++) {
free(domaindetails[i]);
}free(domaindetails);
domaindetails=NULL;
then i called the same for the second as,
char **splitdetails1= split("10000000<delimit>1000<delimit>testing1" , "<delimit>");
it makes error and i can't free the function.
thanks in advance.
Your problem boils down to three basic things:
sizeof is not strlen()
Assignment doesn't copy strings in C.
strncpy() doesn't always nul-terminate strings.
So, when you say something like:
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
thisdoes not copy the string. The first one allocates the size of loc1, which is a char *. In other words, you allocated the size of a pointer. You want to allocate storage to store the string, i.e. using strlen():
arraylist[i]=malloc(strlen(loc1) + 1);
Note the + 1 as well, because you also need room for the nul-terminator. Then, to copy the string you want to use strcpy():
strcpy(arraylist[i], loc1);
The way you had it was just assigning a pointer to your old string (and in the process leaing the memory you had just allocated). It's also common to use strdup() which combines both of these steps, i.e.
arraylist[i] = strdup(loc1);
This is convenient but strdup() is not part of the official C library. You need to assess the portability needs of your code before you consider using it.
Additionally, with strncpy(), you should be aware that it does not always nul-terminate:
strncpy(buf, loc1, loc-loc1);
This copies less bytes than were in the original string and doesn't terminate buf. Thus, it's necessary to include a nul terminator yourself:
buf[loc - loc1] = '\0';
This is the root cause of what you are seeing with the garbage. Since you didn't nul terminate, C doesn't know where your string ends and so it keeps on reading whatever happens to be in memory.

c remove the first character of an array

I have a string:
str1 = "abcabcabc";
How can I remove the first character? I would like the end result to be:
str1 = "bcabcabc";
If you have a character pointer to a string like:
char *s = "This is my string";
then you can just do s++.
If you have a character array, your best bet may be to have a pointer to that array as well:
char s[] = "This is my string";
char *ps = s;
then you can do ps++ and make sure you use ps rather than s.
If you don't want to have a separate pointer to your array then you can use memmove to copy the data:
memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)
though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.
Another solution is to simply code up a loop:
for (char *ps = s; *ps != '\0'; ps++)
*ps = *(ps+1);
*ps = '\0';
This will work for all strings, empty or otherwise.
Pointer tricks (zero-cost):
char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"
Or:
char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"
In-place via memmove:
char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"
Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.
Into a new string via strcpy:
char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"
Into a new string via C++'s std::string::substr:
std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"
Into a new string via C++'s std::copy:
std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"
There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)
If you really meant to say
char str1 [] = "abcabcabc";
Then the easiest thing is
str1 = &str1[1];
If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.
If you really meant C++ and you're using the string object then you can use
str1 = str1.substr(1);
Here is one way to do it:
int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer.
The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.
#include <stdio.h>
#include <conio.h>
main(){
char a[10];
int i;
gets(a);
for (i = 0; a[i] != '\0'; i++) {
a[i] = a[i + 1];
}
printf("\n");
puts(a);
getch();
}
#include <stdio.h>
int main() {
char a[15] = "!Hello world!";
sprintf(a,"%s",a+1);
printf("%s",a);
}

Resources