C program printing weird characters - c

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.

Related

Concatenate char array and char

I am new to C language. I need to concatenate char array and a char. In java we can use '+' operation but in C that is not allowed. Strcat and strcpy is also not working for me. How can I achieve this? My code is as follows
void myFunc(char prefix[], struct Tree *root) {
char tempPrefix[30];
strcpy(tempPrefix, prefix);
char label = root->label;
//I want to concat tempPrefix and label
My problem differs from concatenate char array in C as it concat char array with another but mine is a char array with a char
Rather simple really. The main concern is that tempPrefix should have enough space for the prefix + original character. Since C strings must be null terminated, your function shouldn't copy more than 28 characters of the prefix. It's 30(the size of the buffer) - 1 (the root label character) -1 (the terminating null character). Fortunately the standard library has the strncpy:
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = root->label;
tempPrefix[buffer_size - 1] = '\0';
It's also worthwhile not to hard code the buffer size in the function calls, thus allowing you to increase its size with minimum changes.
If your buffer isn't an exact fit, some more legwork is needed. The approach is pretty much the same as before, but a call to strchr is required to complete the picture.
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = tempPrefix[buffer_size - 1] = '\0';
*strchr(tempPrefix, '\0') = root->label;
We again copy no more than 28 characters. But explicitly pad the end with NUL bytes. Now, since strncpy fills the buffer with NUL bytes up to count in case the string being copied is shorter, in effect everything after the copied prefix is now \0. This is why I deference the result of strchr right away, it is guaranteed to point at a valid character. The first free space to be exact.
strXXX() family of functions mostly operate on strings (except the searching related ones), so you will not be able to use the library functions directly.
You can find out the position of the existing null-terminator, replace that with the char value you want to concatenate and add a null-terminator after that. However, you need to make sure you have got enough room left for the source to hold the concatenated string.
Something like this (not tested)
#define SIZ 30
//function
char tempPrefix[SIZ] = {0}; //initialize
strcpy(tempPrefix, prefix); //copy the string
char label = root->label; //take the char value
if (strlen(tempPrefix) < (SIZ -1)) //Check: Do we have room left?
{
int res = strchr(tempPrefix, '\0'); // find the current null
tempPrefix[res] = label; //replace with the value
tempPrefix[res + 1] = '\0'; //add a null to next index
}

Strange behavior of sscanf

I found some strange thing. Here is example of code:
...
char *start = strchr(value, '(');
if(start)
{
char buf[LEN];
memset(buf, 0, LEN);
int num = sscanf(start, "(%s)", buf);
if(num)
{
buf[strlen(buf) - 1] = '\0';
sprintf(value, "%s", buf);
}
...
if value is "(xxx)", for example, then value will be "xxx" after this actions.
But if value is "([34]xx{4,7}| 1234567890)" then value will be "[34]xx{4,7}".
Can anyone explain it?
P.S. it's ARM platform.
int num = sscanf(start, "(%s)", buf);
Here, sscanf returns when it encounters a whitespace in the buffer pointed to by start. You have a space in your input string:
"([34]xx{4,7}| 1234567890)"
^ space here
scanf returns the number of input items successfully matched and assigned. Here, it will return 1 and the value of num is 1. Next, you overwrite the last character in buf by this statement in your if block.
buf[strlen(buf) - 1] = '\0';
That explains your program's output. Now, a few things about your code:
You don't need to do memset(buf, 0, LEN);. Simply do char buf[LEN] = {0}; This fills the array with the null byte.
sscanf doesn't check for the array bound of the buffer buf into which you are writing the string which sscanf is reading from start. If the size of buf is not enough, sscanf will try to write in the memory beyond the buffer buf. This will lead to undefined behaviour and even program crash because of illegal memory access. You should give field width in the format string of sscanf to guard against the buffer overrun.
#define STRINGIFY(s) #s // preprocessor command # stringifies the token s
#define XSTRINGIFY(s) STRINGIFY(s)
#define LEN 10 // max buffer length without the null byte
// inside a function
char buf[LEN + 1]; // +1 for the null byte
const char *format = "(" XSTRINGIFY(LEN) "%s)"; // "(%10s)"
int num = sscanf(start, format, buf);
The 10 in the format string "(%10s)" means that at most 10 characters are stored in the buffer pointed to by buf and then a null byte \0 is added automatically in the end. Hence you don't need the following in the if block:
buf[strlen(buf) - 1] = '\0'; // overwrites the last char before null byte in buf.
Doing this, in fact, overwrites the last character in buf because strlen doesn't count the null byte.
sscanf is used with %s, when it encounters whitespace it will terminate. That is the reason you are getting the output as "[34]xx{4,7}" instead of expected behaviour
The format string consists of a sequence of directives which describe how to process the sequence of input characters. If processing of a directive fails, no further input is read, and scanf() returns. A "failure" can be either of the following: input failure, meaning that input characters were unavailable, or matching failure, meaning that the input was inappropriate (see below).
In your case, sscanf matches the starting (, and then parses the next token, %s which consumes data up to the first whitespace character. sscanf then fails to match a ), which means that the parsing stops. One token was successfully read and assigned, so the return value is 1.
Note that when using scanf, you cannot detect matching failures that occur after the last token that is assigned.

memcpy prepending instead mem write?

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.

Strchr and strncpy Misuse

Hi im trying to find the - char and then place the leftmost characters into a string. Here i would like FUPOPER to be stored in program_id_DB, however when i run this code my output results to:
Character '-' found at position 8.
The prgmid contains FUPOPERL <-where is it getting this l?!?!
char data_DB[]="FUPOPER-$DSMSCM.OPER*.FUP";
char program_id_DB[10];
char program_name_DB_c[ZSYS_VAL_LEN_FILENAME];
char *pos = strchr(data_DB, '-');
if (pos)
strncpy(program_id_DB,data_DB, pos-data_DB);
printf("Character '-' found at position %d.\n", pos-data_DB+1);
printf("The prgmid contains %s\n",program_id_DB);
You didn't initialize program_id_DB, so it's free to contain anything it wants. Set it to zero before you start:
memset(program_id_DB, 0, 10);
(You need to #include <string.h> for memset.)
In fact, what you're doing is terribly dangerous because there's no guarantee that the string you pass to printf is null-terminated! Always zero the array before use and copy at most 9 non-null characters into it.
You need to put a \0 to mark the string's end.
A way to do it is: memset(program_id_DB, 0, sizeof(program_id_DB)); before you strncpy to it.
You have to append a null-terminating character at the end of the program_id_DB string as strncpy does not do this automatically for you if you've already copied N characters (i.e., in your case you're copying a total of eight characters, so there will not be a null-terminating character copied into the buffer if you copy more than seven characters). Either that, or zero-initialize your program-id_DB string using memset before using it with strncpy.
strncpy is a bitch!
It doesn't terminate the string. You need to terminate the string yourself.
if (pos) {
strncpy(program_id_DB,data_DB, pos-data_DB);
program_id_DB[pos - data_DB] = 0;
}
And if the string is too small, strncpy will set the remainder with zeros.
strncpy(dst, src, 1000); /* always writes 1000 bytes, whether it needs to */

C: Writing and Reading a string to and from a binary file

I want to store strings in a binary file, along with a lot of other data, im using the code below (when i use it for real the strings will be malloc'd) I can write to the file. Ive looked at it in a hex editor. Im not sure im writing the null terminator correctly (or if i need to). when i read back out i get the same string length that i stored, but not the string. what am i doing wrong?
FILE *fp = fopen("mybinfile.ttt", "wb");
char drumCString[6] = "Hello\0";
printf("%s\n", drumCString);
//the string length + 1 for the null terminator
unsigned short sizeOfString = strlen(drumCString) + 1;
fwrite(&sizeOfString, sizeof(unsigned short), 1, fp);
//write the string
fwrite(drumCString, sizeof(char), sizeOfString, fp);
fclose(fp);
fp = fopen("mybinfile.ttt", "rb");
unsigned short stringLength = 0;
fread(&stringLength, sizeof(unsigned short), 1, fp);
char *drumReadString = malloc(sizeof(char) * stringLength);
int count = fread(&drumReadString, sizeof(char), stringLength, fp);
//CRASH POINT
printf("%s\n", drumReadString);
fclose(fp);
You are doing wrong while reading.
you have put the & for the pointer variable that's why it gives segmentation fault.
I removed that it works fine and it returns Hello correctly.
int count = fread(drumReadString, sizeof(char), stringLength, fp);
I see a couple of issues, some problematic, some stylistic.
You should really test the return values from malloc, fread and fwrite since it's possible that the allocation can fail, and no data may be read or written.
sizeof(char) is always 1, there's no need to multiply by it.
The character array "Hello\0" is actually 7 bytes long. You don't need to add a superfluous null terminator.
I prefer the idiom char x[] = "xxx"; rather than specifying a definite length (unless you want an array longer than the string of course).
When you fread(&drumReadString ..., you're actually overwriting the pointer, not the memory it points to. This is the cause of your crash. It should be fread(drumReadString ....
A couple of tips:
1
A terminating \0 is implicit in any double quote string, and by adding an additional at the end you end up with two. The following two initializations are identical:
char str1[6] = "Hello\0";
char str2[6] = { 'H', 'e', 'l', 'l', 'o', '\0', '\0'};
So
char drumReadString[] = "Hello";
is enough, and specifying the size of the array is optional when it is initialized like this, the compiler will figure out the required size (6 bytes).
2
When writing a string, you might just as well just write all characters in one go (instead of writing one by one character sizeOfString times):
fwrite(drumCString, sizeOfString, 1, fp);
3
Even though not so common for a normal desktop pc scenario, malloc can return NULL and you will benefit from developing a habbit of always checking the result because in embedded environments, getting NULL is not an unlikely outcome.
char *drumReadString = malloc(sizeof(char) * stringLength);
if (drumReadString == NULL) {
fprintf(stderr, "drumReadString allocation failed\n");
return;
}
You don't write the terminating NUL, you don't need to but then you have to think about adding it when reading. ie malloc stringLength + 1 char, read stringLength chars and add a \0 at the end of what has been read.
Now the usual warning: if you are writing binary file the way you are doing here, you have lots of unstated assumptions which make your format difficult to port, sometimes even to another version of the same compiler -- I've seen default alignment in struct changes between compiler versions.
Some more to add to paxdiablo and AProgrammer - if you are going to use malloc in the future, just do it from the get go. It's better form and means you won't have to debug when switch over.
Additionally I'm not fully seeing the use of the unsigned short, if you are planning on writing a binary file, consider that the unsigned char type is generally of size byte, making it very convenient for that purpose.
You Just remove your &drumReadString in the fread function.You simply use drumReadString in that function as ganesh mentioned.Because,drumReadString is an array.Array is similar to pointers which point to the memory location directly.

Resources