I am really frustrated about strncpy function. I did something like this:
char *md5S; //which has been assign with values, its length is 44
char final[32];
strncpy(final,md5S,32);
but somehow the length of char final[] became more than 32 after.
What should I do here?
You forgot to leave room for the null character
char final[33];
strncpy(final,md5S,32);
final[32] = '\0';
strncpy does not NUL-terminate the copied string if the source string is as long as or longer than n characters. If you have access to it, you can use strlcpy, which will NUL terminate for you.
Do this instead:
strncpy(dst, src, dstlen - 1);
dst[dstlen - 1] = '\0';
OR
strlcpy(dst, src, dstlen);
where, for a char array, dstlen = sizeof(dst).
If your output buffer isn't large enough to copy all of the source string and its trailing NUL then the output string will not be NUL terminated.
In your case, the MD5 is 33 bytes including the NUL, so the NUL isn't copied. When you read the string back you're reading past the end of your buffer.
Make final 33 bytes long, and ALWAYS add a NUL to the last character in the destination when using strncpy.
int n = 32;
char *src = "some really really long, more than 32 chars, string."
char dst[n+1];
strncpy(dst, src, n);
dst[n] = '\0';
Related
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
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.
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 */
As simple as that. I'm on C++ btw. I've read the cplusplus.com's cstdlib library functions, but I can't find a simple function for this.
I know the length of the char, I only need to erase last three characters from it. I can use C++ string, but this is for handling files, which uses char*, and I don't want to do conversions from string to C char.
If you don't need to copy the string somewhere else and can change it
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
name[namelen - 3] = 0;
If you need to copy it (because it's a string literal or you want to keep the original around)
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
strncpy(copy, name, namelen - 3);
/* add a final null terminator */
copy[namelen - 3] = 0;
I think some of your post was lost in translation.
To truncate a string in C, you can simply insert a terminating null character in the desired position. All of the standard functions will then treat the string as having the new length.
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[] = "one one two three five eight thirteen twenty-one";
printf("%s\n", string);
string[strlen(string) - 3] = '\0';
printf("%s\n", string);
return 0;
}
If you know the length of the string you can use pointer arithmetic to get a string with the last three characters:
const char* mystring = "abc123";
const int len = 6;
const char* substring = mystring + len - 3;
Please note that substring points to the same memory as mystring and is only valid as long as mystring is valid and left unchanged. The reason that this works is that a c string doesn't have any special markers at the beginning, only the NULL termination at the end.
I interpreted your question as wanting the last three characters, getting rid of the start, as opposed to how David Heffernan read it, one of us is obviously wrong.
bool TakeOutLastThreeChars(char* src, int len) {
if (len < 3) return false;
memset(src + len - 3, 0, 3);
return true;
}
I assume mutating the string memory is safe since you did say erase the last three characters. I'm just overwriting the last three characters with "NULL" or 0.
It might help to understand how C char* "strings" work:
You start reading them from the char that the char* points to until you hit a \0 char (or simply 0).
So if I have
char* str = "theFile.nam";
then str+3 represents the string File.nam.
But you want to remove the last three characters, so you want something like:
char str2[9];
strncpy (str2,str,8); // now str2 contains "theFile.#" where # is some character you don't know about
str2[8]='\0'; // now str2 contains "theFile.\0" and is a proper char* string.
I'm having difficulty with strncpy. I'm trying to split a string of 8 characters in two (the first 6 characters in one substring and then the remaining 2 characters in another). To illustrate the particular difficulty I have simplified my code to the following:
include stdio.h
include stdlib.h
include string.h
define MAXSIZE 100
struct word {
char string[8];
char sub1[2];
char sub2[6];
};
typedef struct word Word;
int main(void)
{
Word* p;
p=(Word*)malloc(MAXSIZE*sizeof(Word));
if (p==NULL) {
fprintf(stderr,"not enough memory");
return 0;
}
printf("Enter an 8-character string: \n");
scanf("%s",p->string);
strncpy(p->sub2,p->string,6);
strncpy(p->sub1,p->string,2);
printf("string=%s\n",p->string);
printf("sub1=%s\n",p->sub1);
printf("sub2=%s\n",p->sub2);
free(p);
return 0;
}
The user is prompted for an input. Suppose they input "12345678". Then the output of the program is:
string=1234567812123456
sub1=12123456
sub2=123456
The output I am expecting would be as follows:
string=12345678
sub1=12
sub2=123456
I don't understand how strncpy seems to be appending numbers to string... Obviously I don't understand strncpy well enough, but can anyone explain to me what's going on?
C strings need to be terminated with a null character (0).
strncpy does not put a null terminator on the string for you. If you want a 2-character string, you need to allocate room for three characters, and set the final one to null.
Try this:
struct word {
char string[9];
char sub1[3];
char sub2[7];
};
// ...
strncpy(p->sub2,p->string,6);
p->sub2[6] = 0;
strncpy(p->sub1,p->string,2);
p->sub1[2] = 0;
// ...
Note that if the user inputs more characters than you've allocated room for, you'll end up with problems.
You may find this part of the strncpy documentation useful:
The strncpy() function is similar, except that at most n bytes of src
are copied. Warning: If there is no null byte among the first n bytes
of src, the string placed in dest will not be null terminated.
You are printing strings that are not null-terminated. To fix this declare sub1 and sub2 with an extra char for the terminator:
char sub1[3];
char sub2[7];
And then null terminate after copying:
strncpy(p->sub2,p->string,6);
p->sub2[6] = '\0';
strncpy(p->sub1,p->string,2);
p->sub1[2] = '\0';
The strncpy() function copies at most
n characters from s2 into s1. If
s2 is less than n characters long, the remainder of s1 is filled
with `\0' characters. Otherwise, s1 is not terminated.
So given your string is longer, the strings are not zero terminated. When you print them, prinf is printing the characters you copied, but then carrying on printing whatever is there until it hits a NUL
Althoug scanf does NUL terminate its string, you've not allocated enough space. String in your stuct needs to be 9 characters long - 8 for the characters (12345678) and one more for the NUL. Right now the NUL is going in the first character of str1 - which you then overwrite with the strncpy