Trying to troubleshoot concatenating a string in C - 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;
}

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

unite two strings by copying one by one the characters of the second at the end of the first

this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.

Shifting a char array prior to adding to it

I want to insert characters into the middle of a char array in C, but first I want to shift it to the right each time prior to adding a char so that I don't lose what's already in the char array (called input) by overwriting.
I assume you are terminating the array with a null char since you are using strlen. In that case, I'm pretty sure the first iteration of your for loop will overwrite the null character with the preceding char, and you don't seem to replace it. Try running
for( k = strlen(input) + 1; k > place42; k--)...
This should replace your null character so that your array is properly terminated. Of course you should also be sure you are not overflowing your array and writing on memory that doesn't belong to you.
Why not a write a generic insert routine using the standard C string functions? Something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// insert "ins" into "src" at location "at"
char *insert(char *src, char *ins, int at) {
char dst[strlen(src) + strlen(ins) + 1];
strncpy(dst, src, at);
strcpy(dst + at, ins);
strcpy(dst + at + strlen(ins), src + at);
return strdup(dst);
//return strcpy(src, dst); // you could return this if you know src is long enough
}
int main(void) {
char *src = "abcdef";
char *ins = "123";
printf("%s\n", insert(src, ins, 3));
return 0;
}
prints
abc123def

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

What is a safe way to join strings in 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.

Resources