char str[50];
char strToCopy[16];
int numberOfBytesToFill = 7; // fills 1st n bytes of the memory area pointed to
char charToFillInAs = '*'; //48: ascii for '0' // '$';
void* targetStartAddress = str;
strncpy(strToCopy, "tO sEe The wOrLd", strlen("tO sEe The wOrLd")+1);
puts(strToCopy); // print
strcpy(str, "Test statement !##$%^&*()=+_~```::||{}[]");
puts(str); // print
memset(targetStartAddress, charToFillInAs, numberOfBytesToFill); // fill memory with a constant byte (ie. charToFillInAs)
puts(str); // print
memcpy(targetStartAddress, strToCopy, strlen(strToCopy)+1); // +1 for null char
puts(str); // print
The output is:
tO sEe The wOrLd
Test statement !##$%^&*()=+_~```::||{}[]
*******atement !##$%^&*()=+_~```::||{}[]
tO sEe The wOrLd*******atement !##$%^&*()=+_~```::||{}[]
Hence, my question is why
tO sEe The wOrLd*******atement !##$%^&*()=+_~```::||{}[]
instead of
tO sEe The wOrLd\0#$%^&*()=+_~```::||{}[]
with '\0' as the null char?
strncpy(strToCopy, "tO sEe The wOrLd", strlen("tO sEe The wOrLd")+1);
This is the wrong way to use strncpy. You should specify the size of the output buffer, not the size of the input. In this case the output buffer is 16 bytes, but you are copying 17 bytes into it, which results in undefined behavior.
Note that even if you do specify the output buffer size, strncpy won't write the null terminator if the string is truncated so you'd need to add it yourself:
strncpy(strToCopy, "tO sEe The wOrLd", sizeof(strToCopy));
strToCopy[sizeof(strToCopy)-1] = '\0'; //null terminate in case of truncation.
For this reason, some people prefer to use another function. For example, you can implement a safe copy function by using strncat:
void safeCopy(char *dest, const char *src, size_t destSize) {
if (destSize > 0) {
dest[0] = '\0';
strncat(dest, src, destSize-1);
}
}
To be used like:
safeCopy(strToCopy, "tO sEe The wOrLd", sizeof(strToCopy));
Note also that you won't actually see the null character and what comes after it as in your expected output. The output will simply stop at the null terminator because it indicates the end of the string.
Related
I have:
char *var1 = "foo";
char *var2 = "bar";
and I want to create this string: "foo\0bar\0"
How can I do that? I tried this but of course it does not work:
sprintf(buffer, "%s\0%s", var1, var2);
You have two problems here:
Putting \0 (aka NUL) in the middle of any string is legal, but it also means all C string APIs will consider the string as ending early; every C-style string ends with NUL, and there's no way to tell the difference between a new NUL you added and the "real NUL", because it has to assume the first NUL encountered is the end of the string (reading further could read uninitialized memory, or read beyond the end of the array entirely, invoking undefined behavior). So even if you succeed, C APIs that work with strings will never see bar. You'd have to keep track of how long the "real" string was, and use non-string APIs to work with it (sprintf does return how many characters it printed, so you're not operating completely blind).
Trying to put the \0 in the format string itself means that sprintf thinks the format string ends there; from its point of view, "%s\0%s" is exactly the same as "%s", it literally can't tell them apart.
You can work around problem number 2 by inserting the NUL with a format code that inserts a single char (where NUL is not special), e.g.:
sprintf(buffer, "%s%c%s", var1, '\0', var2);
but even when you're done, doing printf("%s", buffer); will only show foo (because the embedded NUL is where scanning stops). The data is there, and can be accessed, just not with C string APIs:
#include <stdio.h>
int main(int argc, char **argv) {
char *var1 = "foo";
char *var2 = "bar";
char buffer[10] = "0123456789";
sprintf(buffer, "%s%c%s", var1, '\0', var2);
for (int i = 0; i < sizeof(buffer); ++i) {
printf("'%c': %hhd\n", buffer[i], buffer[i]);
}
return 0;
}
Try it online!
which outputs:
'f': 102
'o': 111
'o': 111
'': 0
'b': 98
'a': 97
'r': 114
'': 0
'8': 56
'9': 57
The empty quotes contain a NUL byte if you look at the TIO link, but lo and behold, my browser stops the copy/paste at the NUL byte (yay C string APIs), so I can't actually copy it here.
This is a fairly common problem when dealing with binary data.
If you want to manipulate binary data, don't use the string tools of strcat, strcpy, etc., because they use null-termination to determine the length of the string.
Instead use the memcpy library routine that requires you to specify a length. Keep track of every binary string as a pointer and a length.
char *var1="foo";
unsigned len1 = 3;
char *var2="bar";
unsigned len2 = 3;
/* write var1 and var2 to buffer with null-separation */
/* assuming buffer is large enough */
char buffer[10];
unsigned len_buffer = 0;
/* write var1 to start of buffer */
memcpy(buffer, var1, len1);
len_buffer = len1;
/* append null */
buffer[len_buffer++] = '\0';
/* append var2 */
memcpy(buffer+len_buffer, var2, len2);
len_buffer += len2;
Not particulary fast or short, but this should do the job
strcpy (buffer, var1);
strcat (buffer+strlen(var1)+1, var2);
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.
I have a program that reads the content of a file and saves it into buf. After reading the content it is supposed to copy two by two chars to an array. This code works fine if I'm not trying to read from a file but if I try to read it from a file the printf from buffer prints the two chars that I want but adds weird characters. I've confirmed and it's saving correctly into buf, no weird characters there. I can't figure out what's wrong... Here's the code:
char *buffer = (char*)malloc(2*sizeof(char));
char *dst = buffer;
char *src = buf;
char *end = buf + strlen(buf);
char *baby = '\0';
while (src<= end)
{
strncpy(dst, src, 2);
src+= 2;
printf("%s\n", buffer);
}
(char*)malloc(2*sizeof(char)); change to malloc(3*sizeof*buffer); You need an additional byte to store the terminating null character which is used to indicate the end-of-string. Aslo, do not cast the return value of malloc(). Thanks to unwind
In your case, with strncpy(), you have supplied n as 2, which is not having any scope to store the terminating null byte. without the trminating null, printf() won't be knowing where to stop. Now, with 3 bytes of memory, you can use strcpy() to copy the string properly
strncpy() will not add the terminating null itself, in case the n is equal to the size of supplied buffer, thus becoming very very unreliable (unlike strcpy()). You need to take care of it programmatically.
check the man page for strncpy() and strcpy() here.
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.
I wrote a program in ANSI C to remove the double quote in front and in the end of a string, so "Hello, world" would become Hello, world:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* removeQuotes(char str[]) {
int i = 1;
int len = strlen(str) - 2;
char * tmp = (char*) malloc (sizeof(char) * len);
for (;i<=len;++i ) {
tmp[i-1] = str[i];
}
return tmp;
}
int main(void) {
char str[] = "Hello, world";
char * abc = removeQuotes(str);
printf("Inside the quotes is: %s length: %d\n"
"Original is: %s length: %d", abc, strlen(abc), str, strlen(str));
return 0;
}
In IDEOne (http://ideone.com/Iybuk) I get the correct answer. But GCC gives me something weird:
U→┬↓ length: 22es is: ello, worlESSOR_↑
Original is: Hello, world length: 12
It happens only when the string contains a space. It works fine with "Helloworld" or something like that.
Any robust method to get it work correctly?
You have not allocated enough space for the null terminator.
You don't add the null terminator to the end of your result.
Your source string doesn't actually contain quotes.
In C strings are terminated by a null character, that means '\0'.
You didn't terminate string in removeQuotes(), this is the correct version:
char* removeQuotes(char str[]) {
int i = 1;
int len = strlen(str) - 2;
char * tmp = (char*) malloc (sizeof(char) * (len + 1));
for (;i<=len;++i ) {
tmp[i-1] = str[i];
}
tmp[len] = '\0';
return tmp;
}
Also, your string actually didn't contain quotes and you do not check if the string you pass to removeQuotes contain any quotes.
In your removeQuotes function you underallocate memory for the resulting string and write an extra character past the buffer.
The string "Hello world" doesn't actually contain any quotes. You'd have to declare it as "\"Hello world\"" to have the string you had in mind. In any case, the string resulting from your quote removal has the same number of characters as the input one. You lose the first character, because you never copy it, and the last one gets written past the buffer (and it would be written there, clobbering memory, even if it were a quote mark.
Why do you need to do this anyway? Do you believe that C strings are created with quote characters in the first and last positions of the character array?
Keep a '\0' in temp string. otherwise it will not know that it is a string.