concatenation of character arrays in c - c

I am trying to concatenate 2 character arrays but when I try it does not work and my o/p console hangs and does not print anything.
char *str[2];
str[0] = "Hello ";
str[1] = "World";
strcat(str[0],str[1]);
printf("%s\n",str[0]);
I even tried the below code which fails as well
char *str1 = "Hello ";
char *str2 = "World";
strcat(str1,str2);
printf("%s\n",str1);
Can someone explain this?
TIA.

To concatenate two strings you either have to create a new one large enough tp contain the both source strings or the one of the strings shall be large enough to hold the second appended string.
Take into account that string literals are immutable in C (and C++). Any attempt to change a string literal results in undefined behaviour.
You could concatenate strings if one of them was stored in a character array.
For example
char str1[12] = "Hello ";
const char *str2 = "World";
strcat( str1, str2 );
puts( str1 );
Or you could create a third string.
const char *str[2];
str[0] = "Hello ";
str[1] = "World";
char *str1 = malloc( strlen( str[0] ) + strlen( str[1] ) + 1 );
strcpy( str1, str[0] );
strcat( str1, str[1] );
puts( str1 );
free( str1 );

This code illustrates the problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *str1 = "Hello ";
char *str2 = "World";
char *ptr1, *ptr2;
printf("Find the end of str1...\n");
ptr1 = str1;
while (ptr1[0] != '\0') {
ptr1++;
}
printf("Copy str2 to the end of str1...\n");
ptr2 = str2;
while (ptr2[0] != '\0') {
printf("Attempt to write to read-only memory...\n");
ptr1[0] = ptr2[0];
printf("We never get here.\n");
ptr1++;
ptr2++;
}
ptr2[0] = '\0';
printf("Done.\n");
return 0;
}
Output
Find the end of str1...
Copy str2 to the end of str1...
Attempt to write to read-only memory...
Bus error: 10

Related

C pass char pointer by reference into a function executing strtok() but after returned print unexpected results

I want to test pass pointer by reference in C, below is my test code.
I expect the result to be: "World!", but after I executed, I found that the result is indeterminate.
void parse(char **p)
{
char str[] = "Hello World!";
char *token = strtok(str, " "); // token points to 'H'
*p = strtok(NULL, " "); // *p (buf) points to 'W'
}
int main()
{
char *buf = (char*)malloc(20 * sizeof(char));
buf = "How are you?";
parse(&buf);
printf("%s\n", buf);
}
My View:
(1) In main(): buf points to 'H' ("How are you?"'s first char 'H') (Suppose address of 'H' is 0x10)
(2) parse(&buf) makes pointer p points to buf (i.e. *p = buf = 0x10)
(3) After 2 times of strtok(), *p (buf) points to 'W' (Suppose address of 'W' is 0x20)
(4) Now, return to main(), buf points to 0x20
(5) I expect printf("%s\n", buf); should print "World!", but instead print something like "garbled text".
I have tried debugging, but I don't think I have mistaken anything above.
Can someone quell my doubts?
Thanks in advance.
This code snippet
char *buf = (char*)malloc(20 * sizeof(char));
buf = "How are you?";
produces a memory leak.
At first memory was dynamically allocated and its address was assigned to the pointer buf and then the pointer was reassigned with the address of the first character of a string literal. As a result the address of the allocated memory was lost.
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior,
You should write at least
strcpy( buf, "How are you?" );
As for the function then its local array with automatic storage duration
void parse(char **p)
{
char str[] = "Hello World!";
//...
will not be alive after exiting the function. So the pointer buf will have an invalid value.
The program can look for example the following way
#include <stdio.h>
#include <string.h>
void parse( char *s, char **p)
{
*p = strtok( s, " " );
*p = strtok(NULL, " ");
}
int main()
{
char str[] = "Hello World!";
char *buf;
parse( str, &buf );
if ( buf ) printf("%s\n", buf);
}

C - string concatenation with pointers

why does the following string concatenation does not work?
main()
{
char *str1 = "United";
char *str2= "Front";
char *str3;
str3 = strcat(str1, str2 ) ;
printf("\n%s",str3 );
}
I got this problem in exercise questions in one of a book on pointers. The question mentions
[Q] Is the code correct if not why and also correct the code.
See my answer to the question concatenation of character arrays in c
You may not change string literals.
This statement
str3 = strcat(str1, str2 ) ;
tries to change the string literal str1 and moreover tries to write beyond the string literal.
To make a concatenated string you have to allocate a memory large enough to contain the both strings.
What you need is the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *str1 = "United";
const char *str2 = "Front";
char *str3 = malloc( strlen( str1 ) + strlen( str2 ) + 1 );
strcpy( str3, str1 );
puts( strcat( str3, str2 ) );
free( str3 );
return 0;
}
The program output is
UnitedFront
When you write char* s = "something" a piece of read-only memory is allocated. More on this here.
The declaration of strcat looks like this:
char *strcat( char *dest, const char *src );
Basically what it will do is append src to dest, but since your destination, str1 does not have enough memory to hold both strings.
So what I would do is, either use snprintf with a pre-allocated buffer or:
char *str1 = "United";
char *str2 = "Front";
char *buf = calloc(strlen(str1) + strlen(str2) + 1, sizeof(char));
strncpy(buf, str1, strlen(str1));
strncat(buf, str2, strlen(str2));
printf("%s", buf);
Or with snprintf:
char *str1 = "United";
char *str2 = "Front";
int buf_len = strlen(str1) + strlen(str2) + 1;
char *buf = calloc(buf_len, sizeof(char));
snprintf(buf, buf_len, "%s%s", str1, str2);
The first parameter of strcat (str1 in your case) needs to have enough allocated memory to hold the concatenated string.
You can either create it with malloc or declare it as an array with a big enough size.

Unknown symbols appear when printing the result

I have two ways to do the same purpose, the first-way prints unknown symbols and the second-way prints exactly what I want.
The first-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
printf("%s\n", str);
free(str);
The result:
The second-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1);
for (int i = 0; i <= strlen(constStr); i++) {
str[i] = constStr[i];
}
printf("%s\n", str);
free(str);
The result:
Why the first-way the result seems strange?
No you didn't null terminate the string. This is undefined behavior to pass pointer to non-null terminated char array in printf using %s format specifier.
Outside the loop make *p=0. That will null terminate the char array.
Second way is printing because you copied the \0 which is in strlen(constStr) index of the array. Notice the <= in the loop condition.
From where those weird letters come?
Think in terms of printf. When it sees the %s format specifier it prints starting from the address provided to it as argument. Now when does it stop? when it finds the \0. here it didnt find it and it read out of the memory that you allocated. Those bit patterns on those memory turned out to be those non printable characters. That's what you saw. The correct way to do this would be:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr) + 1), *p = str;
while (*p++ = *constStr++); // here `\0` will be copied.
printf("%s\n", str);
free(str);
When working with strings make sure you keep the corner cases clean. By that I mean,check whether the \0 is copied or not etc. This is so common a problem when we implement string routines.
To fix the first one, add a null at the end of the string:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
*p = '\0'; /* <-- HERE */
printf("%s\n", str);
free(str);
Note: you are modifying a pointer to a temporary - not recommended. Use the same approach as you did for str, by using a another pointer which gets shifted.

How to add a char/int to an char array in C?

How can I add '.' to the char Array := "Hello World" in C, so I get a char Array: "Hello World." The Question seems simple but I'm struggling.
Tried the following:
char str[1024];
char tmp = '.';
strcat(str, tmp);
But it does not work. It shows me the error: "passing argument 2 of ‘strcat’ makes pointer from integer without a cast"
I know that in C a char can be cast as int aswell. Do I have to convert the tmp to an char array aswell or is there a better solution?
strcat has the declaration:
char *strcat(char *dest, const char *src)
It expects 2 strings. While this compiles:
char str[1024] = "Hello World";
char tmp = '.';
strcat(str, tmp);
It will cause bad memory issues because strcat is looking for a null terminated cstring. You can do this:
char str[1024] = "Hello World";
char tmp[2] = ".";
strcat(str, tmp);
Live example.
If you really want to append a char you will need to make your own function. Something like this:
void append(char* s, char c) {
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
append(str, tmp)
Of course you may also want to check your string size etc to make it memory safe.
The error is due the fact that you are passing a wrong to strcat(). Look at strcat()'s prototype:
char *strcat(char *dest, const char *src);
But you pass char as the second argument, which is obviously wrong.
Use snprintf() instead.
char str[1024] = "Hello World";
char tmp = '.';
size_t len = strlen(str);
snprintf(str + len, sizeof str - len, "%c", tmp);
As commented by OP:
That was just a example with Hello World to describe the Problem. It
must be empty as first in my real program. Program will fill it later.
The problem just contains to add a char/int to an char Array
In that case, snprintf() can handle it easily to "append" integer types to a char buffer too. The advantage of snprintf() is that it's more flexible to concatenate various types of data into a char buffer.
For example to concatenate a string, char and an int:
char str[1024];
ch tmp = '.';
int i = 5;
// Fill str here
snprintf(str + len, sizeof str - len, "%c%d", str, tmp, i);
In C/C++ a string is an array of char terminated with a NULL byte ('\0');
Your string str has not been initialized.
You must concatenate strings and you are trying to concatenate a single char (without the null byte so it's not a string) to a string.
The code should look like this:
char str[1024] = "Hello World"; //this will add all characters and a NULL byte to the array
char tmp[2] = "."; //this is a string with the dot
strcat(str, tmp); //here you concatenate the two strings
Note that you can assign a string literal to an array only during its declaration.
For example the following code is not permitted:
char str[1024];
str = "Hello World"; //FORBIDDEN
and should be replaced with
char str[1024];
strcpy(str, "Hello World"); //here you copy "Hello World" inside the src array
I think you've forgotten initialize your string "str": You need initialize the string before using strcat. And also you need that tmp were a string, not a single char. Try change this:
char str[1024]; // Only declares size
char tmp = '.';
for
char str[1024] = "Hello World"; //Now you have "Hello World" in str
char tmp[2] = ".";
Suggest replacing this:
char str[1024];
char tmp = '.';
strcat(str, tmp);
with this:
char str[1024] = {'\0'}; // set array to initial all NUL bytes
char tmp[] = "."; // create a string for the call to strcat()
strcat(str, tmp); //

Compare two strings - get right part of the longer one

I have two strings, e.g.:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
How to do something like str1 - str2 to get the dddeee substring?
If str2 is guaranteed to be a prefix of str1, then this will suffice:
const char *str3 = &str1[strlen(str2)];
which is equivalent to this: (as #James points out in the comments)
const char *str3 = str1 + strlen(str2);
Of course, str3 is just a pointer into one of the original strings. If the contents of the original string changes, then so will your result. So you may want to create a copy, using malloc() and strcpy() (and then free() at some point).
This will skip the common prefix of two strings:
char* suffix(const char* prefix, const char* str) {
while (*prefix && *str && *prefix == *str) {
prefix++;
str++;
}
return str;
}
For example, if you pass "AAB" and "AACC", this would return "CC".
str3 will contain a copy of the prefix:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
size_t length = strlen1 - strlen2;
char* str3 = calloc(sizeof(char), length + 1);
memcpy(str3, str1+strlen(str2), length);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[] = "aaaabbbbbdddeee";
char b[] = "aaaabbbbb";
const char* start = strstr(a, b);
if (start)
{
printf("%s\n", a + strlen(b));
}
return 0;
}
Since you have clarified that str2 is a prefix of str1, you can get the pointer to the extra part in str2 simply with the operation:
str1 + strlen(2);
For example, to print the "dddeee" part of your string:
printf("%s\n", str1 + strlen(str2));
How this works is simple. str1 + strlen(str2) is a pointer that is strlen(str2) N characters away from the beginning of the string pointed to be str1. strlen(str2) returns the number of characters in the second string and you skip those many characters in the first string and reach the extra part.

Resources