Size definition of strcat() function - c

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.

Related

Problem on strncpy with source string longer than destination array

I tried to think how to make the function strncpy and I met this problem.
char src[] = "123456789A";
char dest[10];
int n = 10;
printf("strncpy:%s\n", strncpy(dest, src, n));
Output
strncpy:123456789A123456789A
What is happening ?
The quick answer: strncpy is not your friend!
strncpy is not a safer version of strcpy, it will copy up to n characters from src and if src is shorter, will pad the destination with null bytes up a total of n characters.
If the source string has n or more characters, the destination array will not be null terminated and passing to printf("%s", will have undefined behavior: printf will keep reading and printing bytes from memory after the end of dest, until it finds a null byte or until this undefined behavior causes other unpredictable side effects...
The semantics of strncpy are counter-intuitive and error-prone, avoid usng this function. See this article for a long answer: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
As others have said strncpy won't include a terminating null if the destination size is the same as the string length. To give you a practical answer I normally just subtract one from the size of the destination using sizeof to get the destination size including space for the terminator:
char src[] = "123456789A";
char dest[10];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));
Which gives an output of "strncpy:123456789" which is a character short of what you want but at least is defined behaviour and lets you know the destination buffer isn't large enough to contain the null terminator. So the final code that gives you the result you're after would be:
char src[] = "123456789A";
char dest[11];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));
The array dest does not contain a string because there is no enough space to accommodate the terminating zero '\0' of the copied source string,
So to output the array use the following statement
printf("strncpy: %*.*s\n", n, n, strncpy(dest, src, n));
Otherwise you have to write something like the following
strncpy( dest, src, n )[sizeof( dest ) - 1] = '\0';
printf("strncpy: %s\n", dest );
In this case the destination array will not have the last character of the source string that will be overwritten by the zero character.
If you want to copy less characters than the size of the destination array then what to do after copying depends on the intention. If you want just to overwrite part of the string that is already stored in the destination array then nothing else you need to do. Otherwise set the character at position n to zero character.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int main(void)
{
char src[] = "123456789A";
char dest[10] = "543216789";
size_t n = 5;
strncpy( dest, src, n );
printf("strncpy: %s\n", dest );
strncpy( dest, "Hello", n )[n] = '\0';
printf("strncpy: %s\n", dest );
return 0;
}
Its output is
strncpy: 123456789
strncpy: Hello

C - Using sprintf() to put a prefix inside of a string

I'm trying to use sprintf() to put a string "inside itself", so I can change it to have an integer prefix. I was testing this on a character array of length 12 with "Hello World" inside it already.
The basic premise is that I want a prefix that denotes the amount of words within a string. So I copy 11 characters into a character array of length 12.
Then I try to put the integer followed by the string itself by using "%i%s" in the function. To get past the integer (I don't just use myStr as the argument for %s), I make sure to use myStr + snprintf(NULL, 0, "%i", wordCount), which should be myStr + characters taken up by the integer.
The problem is that I'm having is that it eats the 'H' when I do this and prints "2ello World" instead of having the '2' right beside the "Hello World"
So far I've tried different options for getting "past the integer" in the string when I try to copy it inside itself, but nothing really seems to be the right case, as it either comes out as an empty string or just the integer prefix itself '222222222222' copied throughout the entire array.
int main() {
char myStr[12];
strcpy(myStr, "Hello World");//11 Characters in length
int wordCount = 2;
//Put the integer wordCount followed by the string myStr (past whatever amount of characters the integer would take up) inside of myStr
sprintf(myStr, "%i%s", wordCount, myStr + snprintf(NULL, 0, "%i", wordCount));
printf("\nChanged myStr '%s'\n", myStr);//Prints '2ello World'
return 0;
}
First, to insert a one-digit prefix into a string “Hello World”, you need a buffer of 13 characters—one for the prefix, eleven for the characters in “Hello World”, and one for the terminating null character.
Second, you should not pass a buffer to snprintf as both the output buffer and an input string. Its behavior is not defined by the C standard when objects passed to it overlap.
Below is a program that shows you how to insert a prefix by moving the string with memmove. This is largely tutorial, as it is not generally a good way to manipulate strings. For short strings, where space is not an issue, most programmers would simply print the desired string into a temporary buffer, avoiding overlap issues.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Insert a decimal numeral for Prefix into the beginning of String.
Length specifies the total number of bytes available at String.
*/
static void InsertPrefix(char *String, size_t Length, int Prefix)
{
// Find out how many characters the numeral needs.
int CharactersNeeded = snprintf(NULL, 0, "%i", Prefix);
// Find the current string length.
size_t Current = strlen(String);
/* Test whether there is enough space for the prefix, the current string,
and the terminating null character.
*/
if (Length < CharactersNeeded + Current + 1)
{
fprintf(stderr,
"Error, not enough space in string to insert prefix.\n");
exit(EXIT_FAILURE);
}
// Move the string to make room for the prefix.
memmove(String + CharactersNeeded, String, Current + 1);
/* Remember the first character, because snprintf will overwrite it with a
null character.
*/
char Temporary = String[0];
// Write the prefix, including a terminating null character.
snprintf(String, CharactersNeeded + 1, "%i", Prefix);
// Restore the first character of the original string.
String[CharactersNeeded] = Temporary;
}
int main(void)
{
char MyString[13] = "Hello World";
InsertPrefix(MyString, sizeof MyString, 2);
printf("Result = \"%s\".\n", MyString);
}
The best way to deal with this is to create another buffer to output to, and then if you really need to copy back to the source string then copy it back once the new copy is created.
There are other ways to "optimise" this if you really needed to, like putting your source string into the middle of the buffer so you can append and change the string pointer for the source (not recommended, unless you are running on an embedded target with limited RAM and the buffer is huge). Remember code is for people to read so best to keep it clean and easy to read.
#define MAX_BUFFER_SIZE 128
int main() {
char srcString[MAX_BUFFER_SIZE];
char destString[MAX_BUFFER_SIZE];
strncpy(srcString, "Hello World", MAX_BUFFER_SIZE);
int wordCount = 2;
snprintf(destString, MAX_BUFFER_SIZE, "%i%s", wordCount, srcString);
printf("Changed string '%s'\n", destString);
// Or if you really want the string put back into srcString then:
strncpy(srcString, destString, MAX_BUFFER_SIZE);
printf("Changed string in source '%s'\n", srcString);
return 0;
}
Notes:
To be safer protecting overflows in memory you should use strncpy and snprintf.

Memmove() in C prints the result twice

I was playing around with memmove and I understand how it works. But whenever the end result contains more than the original source size, it prints out a bunch of random numbers. For example:
char str[] = "abcdefgh";
memmove(str + 6, str + 3, 4);
printf("%s\n", str);
gives me the output abcdefdefgbdefggh when it should give me
abcdefdefg Why is the other characters being added into str?
memmove(void *destination, void *source, size_t bytesToCopy)
The other characters added to the string are characters beyond the memory location of your declared char str[]. You have gone beyond the buffer address in memmove and the terminating character of '\0' has been over written. So when you call printf, the function will continue to print characters referenced by your pointer till it encounters '\0'.
The memory for str looks:
'a','b','c','d','e','f','g','h',0x0,?,?,?
^
End of buffer (terminates the string)
You copy 4 bytes from index 3 to index 6 which gives
'a','b','c','d','e','f','d','e','f','g',?,?
^
End of buffer
So you have
a) overwritten the string termination (0x0) by 'f'
b) written outside the buffer (i.e. 'g') which is really bad
Due to a) you'll get strange results when printing str as the string termination is gone.

StrCat is not working with Single Char String - C

I'm using the code below to add some "0" chars into my string, but it seems there is a problem and the program will crash. Everything seems logic but I do not know where is the problem?
#include <stdlib.h>
#include <string.h>
int main()
{
char *Ten; int i=0; Ten = malloc(12);
Ten="1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
You declare Ten as a pointer to a string literal. However, you cannot rely on being able to modify a string literal, and thus the program crashes.
To fix this, you can declare Ten as an array instead:
int main()
{
char Ten[12]="1"; int i=0;
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
Note that you need 12 bytes; 11 for the characters and one for the terminating NUL character.
Ten is a string literal and you cannot modify it. Try with array instead
char Ten[12] = "1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
notice that I created an array of 12 characters, because there should be room for a termination '\0'.
You actually don't need strcat here, it's just do this
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
for (i = 1 ; i < 11 ; i++)
Ten[i] = '0';
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
or
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
memset(Ten + 1, '0', 10);
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
To quote from strcat manual on linux:
The strcat() function appends the src string to the dest string,
overwriting the terminating 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.
Your Ten array is only long enough to store original literal. You need to preallocate memory as long as final desired string.
String literals might be stored in read only section of memory. Any attempt to modify such a literal causes undefined behavior.
To concatenate two strings, the destination must have enough space allocated for the characters to be added and space for '\0'. Change the declaration of Ten to
char Ten[12] = "1";
and it will work.

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