Weird characters when concatenating strings in c [duplicate] - c

This question already has answers here:
What is the value of an uninitialized string in c? [duplicate]
(6 answers)
Closed 1 year ago.
I'm trying to concatenate multiple strings to create a longer phrase but I get weird, seemingly random, characters in front of the phrase when I try to print it. Here is the code:
char* str2 = argv[2];
int len2 = strlen(str2);
char* str3 = argv[3];
int len3 = strlen(str3);
printf("child PID(%d) receives Y = '%s' and Z= '%s' from the pipe\n",getpid(), str2, str3 );
//get the length of arguments 2 and 3 and create an array that is 1 larger than that (for the space between the two phrases)
//then concatenate them
int catLen = len2+len3;
char conc[catLen + 1];
strcat(conc, str2);
strcat(conc," ");
strcat(conc, str3);
printf("child PID(%d) concatenates Y and Z to generate Y' = '%s'\n",getpid(),conc);
int len1;
//get the length of the first command-line argument in the pipe
read(port[0],&len1,sizeof(len1));
//get the first command-line argument from the pipe
char str1[len1];
read(port[0], &str1,len1);
printf("child PID(%d) reads X from the pipe = '%s'\n",getpid(),str1);
//problems start when concatenating strings here
int totalLen = len1+catLen+1;
char phrase[totalLen];
strcat(phrase, str1);
printf("%s\n",phrase);
strcat(phrase," ");
printf("%s\n",phrase);
strcat(phrase,conc);
printf("child PID(%d) concatenates X and Y' to generate Z' = '%s'\n",getpid(),phrase);
I only encounter this issue when I try and concatenate the second set of strings, and I don't understand why. What is different between how I did it earlier and at the bottom the program?

First of all,
as Ptit Xav points out, you need one additional byte of space for conc. You need len1 bytes for the first string, plus 1 for the space, plus len2 for the second string, and then one more for the terminating null character. So if catLen = len1 + len2, then you should declare char cond[catLen + 2]; (or change the calculation of catLen in some equivalent way).
Next, when you declare a local array like char conc[catLen + 2]; without initializing it, it contains garbage. If you then attempt to strcat onto it, you concatenate onto garbage. If the garbage happens not to contain any null bytes, then strcat will overrun the array searching for a null byte, causing undefined behavior (which is very bad).
So either make your first use a strcpy instead of strcat:
char conc[catLen + 2];
strcpy(conc, str2); // note strcpy here
strcat(conc," ");
strcat(conc, str3);
Or else set the first character of your array to be a null character before starting, so that it becomes an empty string:
char conc[catLen + 2];
conc[0] = '\0'; // conc now contains an empty string
strcat(conc, str2);
strcat(conc," ");
strcat(conc, str3);
You can also initialize the array:
char conc[catLen + 2] = "";
strcat(conc, str2);
strcat(conc," ");
strcat(conc, str3);
However this will cause the program to fill the entire array conc with null bytes, where you really only needed one, so it is inefficient.

Related

Can't enter 2 inputs from user with unknown length of char pointer

I am trying to get 2 inputs from user with unknown length of char pointer.(Working on dynamically allocating memory) But after entering 1st input with a "space" it doesn't wait for user to enter second input, it only reads one word and then it allows second input.
char *str1;
char ch;
printf("Enter a sentence:(Ex: Computer Engineer)");
str1 = (char*)malloc(sizeof(char*));
scanf(" %s", str1);
printf("Enter a character to search(Ex: g):");
scanf(" %c", &ch);
char *result;
result=mystrchr(str1,ch);
if(result!=NULL)
printf("%s",result);
else
printf("NULL");
The second exact same statement of
str1 = (char*) malloc(sizeof(char*));
is redundant, inappropriate and useless. By doing so you allocate another memory space to which str1 is pointing to; leaving the previous allocated space because of no free()ing abandoned but existing in memory.
char *str1;
str1 = (char*) malloc(sizeof(char*));
With that call to malloc() you allocate memory of the size of a pointer to char, usually 4 bytes on most modern systems, not the space needed to store a string like "Computer Engineer". With this definition it is only be able to store a string of 3 characters plus the automatically appended string-terminating null character (4 characters for 4 bytes).
By putting in a string longer than 3 characters by the call to scanf():
scanf(" %s", str1);
the program will write beyond the bounds of the allocated memory, which invokes undefined behavior (like it was high-probably happened in your case).
You need to allocate enough space to hold the provided strings - in the case of f.e. "Computer Engineer" it needs to have at least 18 byte (Note that sizeof(char) == 1):
char *str1 = malloc((sizeof(char) * 18);
or alternatively:
char *str1 = malloc((sizeof(*str1) * 18);
Note that you can´t put in a white space separated word by using the %s format specifier. For achieve that, use %[ instead:
scanf("%[^\n]", str1);
Or even better use the more reliable and safer fgets():
fgets(str1,18,stdin);
If you want to allocate memory dependent upon the input of a user, you need to add another input request and variable before allocating:
int len;
printf("How many characters the string should have?");
scanf("%d",&len);
char *str1 = malloc((sizeof(*str1) * (len + 1)); // +1 element for null character.
printf("Enter a sentence:(Ex: Computer Engineer)");
fgets(str1,len,stdin);
Side note:
You do not need to cast the returned pointer of malloc -> Do I cast the result of malloc?
Programming is not just aligning lines of codes. Memory allocation in C is not very complex but it is very easy to write erroneous code with it (you did...).
This is just err... bad code:
str1 = (char*)malloc(sizeof(char*)); // Wrong: you allocate a char array with
// the size of a char pointer: nonsense
printf("Enter a sentence:(Ex: Computer Engineer)"); // no error here :-)
str1 = (char*)malloc(sizeof(char*)); // Wrong: the previously allocated array is
// now leaked: you can no longer free it
scanf(" %s", str1); // What if input is larger than sizeof(char*)?
Now for your question: scanf reads blank delimited tokens. It is a feature. If you want line oriented input, you should use fgets.
Code could be:
#define SIZE 16
size_t size = SIZE; // initial size of the allocated array
char *str1 = malloc(size); // sizeof(char) is by definition 1
char ch[2]; // a trick to read next non blank character
printf("Enter a sentence:(Ex: Computer Engineer)");
char *str = str1;
for(;;) { // loop to accept arbitrary length input
if (NULL == fgets(str, size, stdin)) {
perror("Input error or end of file");
return 1;
}
if (strchr(str, '\n') != -1) break; // ok we have a full line
str1 = realloc(str1, size * 2);
if (NULL == str1) {
perror("Could not allocate memory");
return 1;
str = str1 + size - 1; // point after currently got data
size = size * 2;
}
printf("Enter a character to search(Ex: g):");
scanf("%1s", ch);
char *result = mystrchr(str1,ch[0]);
...
Beware: code is untested and could contain typos...

creating a string from 2 substrings

I want to create a big string 'des' from 2 substrings copied from string 'scr' this way :
I want to copy the substring, lets call it - 'string1' ( from ptr x to the end of the 'scr' string), then to place it in the 'des' and after that to concatenate it with another substring, lets call it - 'string 2' copied from the 'scr' string from the head of the string to x ptr. How can I do it not using a temp string ?
for example : scr = "ThisIs", string1 = "Is", string2 = "This" des = "IsThis"
I don't want to use a temp string to hold string 1 or string2.
Can you help me?
You don't need a temp string, you only need a pointer to hold the boundary of substrings. Try following:
char src[] = "ThisIs";
char dst[7] = {'\0'};
int len = strlen(src);
int str1len = 4;
strncpy(dst, src + str1len, len - str1len);
strncpy(dst + len - str1len, src, str1len);
printf("src=%s, dst=%s\n", src, dst);
If you know the position of the second string, you can just print the two substrings to the destination string in reverse order:
char *src = "ThisIs"; // source string
char dst[7]; // char buffer for destination string
int pos = 4; // position of second substring
snprintf(dst, sizeof(dst), "%s%.*s", src + pos, pos, src);
puts(dst);
Explanation:
snprintf writes formatted data to a string, just as printf writes formatted data to the screen. It takes the buffer length as second argument and uses it to ensure that the buffer will not overflow. It also guarantees that the resulting string is null terminated.
If the output would be a string with more characters than the buffer can hold, the output is truncated. snprintf returns the length that the string would have if the buffer were ininitely large. You can use that return value to check whether the output was truncated.
The second substring is null-terminated, because it ends where the whole string src ends. You can print it with printf("%s", str + pos), where pos is the start of the substring.
The first substring isn't null terminated. You can print substrings of any length by providing a "precision" to the %s format after a period: printf("%.4s", str).
You can make that precision variable by using an asterisk in the format and then providing an additional int argument before the actual argument: printf("%.*s", 4, str)
This answer is at heart the same answer as fluter's, but it guards against buffer overfloows and involves fewer length calculations.

Size definition of strcat() function

The question is why should I define size of string (string[] should be string[some-number])
When the program is as following it gives me Abort trap: 6:
#include <stdio.h>
#include <string.h>
int main(void)
{
char buffer1[] = "computer";
char string[]="program";
strcat( buffer1, string );
printf( "buffer1 = %s\n", buffer1 );
}
This is the program from http://www.tutorialspoint.com/cprogramming/c_data_types.htm it works fine:
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[12] = "Hello";
char str2[12] = "World";
char str3[12];
int len ;
/* copy str1 into str3 */
strcpy(str3, str1);
printf("strcpy( str3, str1) : %s\n", str3 );
/* concatenates str1 and str2 */
strcat( str1, str2);
printf("strcat( str1, str2): %s\n", str1 );
/* total lenghth of str1 after concatenation */
len = strlen(str1);
printf("strlen(str1) : %d\n", len );
return 0;
}
What is the mistake? Even if I define all of the sizes of strings in my program, my code still gives Abort trap:6?
From the man page of strcat:
DESCRIPTION
The strcat() function appends the src string to the dest string, overwriting the termi‐
nating null byte ('\0') at the end of dest, and then adds a terminating null byte. The
strings may not overlap, and the dest string must have enough space for the result. If
dest is not large enough, program behavior is unpredictable; buffer overruns are a
favorite avenue for attacking secure programs.
When you declare your string, the compiler allocate the size of your initial string to be 9 (resp. 8) for the buffer1 (resp. string) (includin '\0').
Thus, strcat will result in 9 - 1 + 8 (i.e. 16 bytes) but only 9 are available.
Your strcat is buffer overflowing buffer1 which can hold only strlen("computer")+1 bytes. ommitting array size does not mean "dynamic" array! When you specify the size of the array, you are reserving as many bytes as you want: again you need to avoid bufferoverflow of course.
So,
strcpy(str3, str1);
and
strcat( str1, str2);
are ok since str3 size is enough for str1, and str1 is enough for strlen(str1) + strlen(str2) + 1, i.e. exactly 11: 5 (hello) + 5 (world) + 1 (terminator). The magic number 12 was choosen with a reason, big enough to hold both strings and a terminator.
About C strings
C-strings are array of chars where the last is "null", '\0', i.e. they are array of chars where the last one is 0. This terminator is needed so that string related functions can understand where the string ends.
If it happens that a null byte is found in the middle of a string, from the point of view of C string functions, the string will end at that point. E.g.
char buffer1[] = "computer\0program";
// array: { 'c', 'o', ... '\0', 'p', 'r', 'o', .., 'm', '\0' }
// ...
printf("%s\n", buffer1);
will print computer only. But at this point the buffer will be big enough to hold computer and program, a terminator (and another extra byte), since the compiler computed the size of the char array considering the literal sequence of characters which syntactically ends at the second ".
But for all C-string functions, the string contained in buffer1 is computer. Note also that sizeof buffer1 will give the correct size of the buffer, i.e. 17, opposed to the result of strlen(buffer1) which is just 8.
The first parameter of strcat is used to store the result, so it must have enough space for the concatenated string.
In your code:
char buffer1[] = "computer";
is equivalent to:
char buffer1[9] = "computer";
defines a char array with just enough space for the string "computer", but not enough space for the result.
char buffer1[] = "computer";
Creates a buffer big enough to hold 9 characters (strlen("Hello" + 1 byte for \0)). If you write anymore data to it what you end up with is Undefined behavior (UB). This is what happens when you do a strcat.
UB means the program might crash or show literally any behavior. You are rather lucky that a program with UB crashes because it does not need to, but if it does atleast there is a indication of something wrong in it. Most of the times programs with UB will continue running correctly and crash when you least expect or want them to.

String Pointer Modification [duplicate]

This question already has answers here:
What is the difference between char a[] = ?string?; and char *p = ?string?;?
(8 answers)
How do I concatenate const/literal strings in C?
(17 answers)
Closed 10 years ago.
How can I take a C string pointer like
char *a = "asdf";
and change it so that it becomes
char *a = "\nasdf\n";
When you assign string like tihs
char *a = "asdf";
you are creating a string literal. So it cannot be modified. It is already explained here.
You can't modify a string literal, so you would have to create a second string with that new format.
Or, if the formatting is just for display, you can hold off on creating a new string by just applying the formatting when you display it. Eg:
printf("\n%s\n", a);
I don't know whether this is what you were looking for, but it looks like you want to concatenate strings: How do I concatenate const/literal strings in C?
Use "\n" as your first and last string, and the string given as the second one.
You can't do that if you are using pointers to string literals, the reason being that a string literal is constant and can't be changed.
What you can do is declare an array, with enough space to accommodate the extra characters, something like
char a[16] = "asdf";
Then you can e.g. memmove to move the string around, and add the new characters manually:
size_t length = strlen(a);
memmove(&a[1], a, length + 1); /* +1 to include the terminating '\0' */
a[0] = '\n'; /* Add leading newline */
a[length + 1] = '\n'; /* Add trailing newline */
a[length + 2] = '\0'; /* Add terminator */
char* a = "asdf";
char* aNew = new char[strlen(a) + 2]; //Allocate memory for the modified string
aNew[0] = '\n'; //Prepend the newline character
for(int i = 1; i < strlen(a) + 1; i++) { //Copy info over to the new string
aNew[i] = a[i - 1];
}
aNew[strlen(a) + 1] = '\n'; //Append the newline character
a = aNew; //Have a point to the modified string
Hope this is what you were looking for. Don't forget to call "delete [] aNew" when you're finished with it to prevent it from leaking memory.

Confused with the char array when scanf

I am confused with one tiny program.
#include <stdio.h>
#define LEN 10
int main()
{
char str1[LEN] = "\0";
char str2[LEN] = "\0";
scanf("%s", str1);
scanf("%s", str2);
printf("%s\n", str1);
printf("%s\n", str2);
return 0;
}
If my input are:
mangobatao
mangobatao123456
Why should the output be:
123456
mangobatao123456
And not:
mangobatao
mangobatao123456
How has the char array has been allocated in the memory?
Well, a 10 character char array won't fit "mangobatao", since it has 10 characters - there's no room for the null terminator. That means you've caused undefined behaviour, so anything could happen.
In this case, it looks like your compiler has laid out str2 before str1 in memory, so when you call scanf to fill str2, the longer string overwrites the beginning of str1. That's why you see the end of what you think should be in str2 when trying to print str1. Your example will work fine if you use a length of 100.
I think your compiler has allocated space for str2[10] just 10 characters before the str1 pointer.
Now, when you scanf a string of length 16 at str2, the string terminator '\0' is appended at str2 + 17th position, which is infact str1 + 7.
Now when you call printf at str1, the characters read are actually str2 + 11, str2 + 12,..., str2 + 16 until the null terminator is encountered at str2 + 17 (or str1 + 7).
The printf at str2 must be obvious.

Resources