You forgot to leave room for the null character
char final[33];
strncpy(final,md5S,32);
final[32] = '\0';
Answer from rouzier on Stack OverflowYou 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).
I just fell foul of the fact that strncpy does not add an old terminator if the destination buffer is shorter than the source string. Is there a single function standard library replacement that I could drop in to the various places strncpy is used that would copy a null terminated string up to the length of the destination buffer, guaranteeing early (but correct) termination of the destination string, if the destination buffer is too short?
Edit:
-
Yes, I do need C-null terminated strings. This C API is called by something else that provides a buffer for me to copy into, with the expectation that it’s null terminated
Edit 2:
-
I know I can write a helper function that’s shared across relevant parts of the code, but I don’t want to do that because then each of those modules that need the function becomes coupled to a shared helper header file, which is fine in isolation but “oh I want to use this code in another project, better make sure I take all the misc dependencies” is best avoided. Necessary if necessary, but if possible using a standard function, even better.
Implementing a string copy function in C - Stack Overflow
string - Copying n chars with strncpy more efficiently in C - Stack Overflow
Statically copy C-string of variable length - Stack Overflow
c++ - Proper way to copy C strings - Stack Overflow
Videos
Good interview question has several layers, to which to candidate can demonstrate different levels of understanding.
On the syntactic 'C language' layer, the following code is from the classic Kernighan and Ritchie book ('The C programming language'):
while( *dest++ = *src++ )
;
In an interview, you could indeed point out the function isn't safe, most notably the buffer on *dest isn't large enough. Also, there may be overlap, i.e. if dest points to the middle of the src buffer, you'll have endless loop (which will eventually creates memory access fault).
As the other answers have said, you're overwriting the buffer, so for the sake of your test change it to:
char buffer[ 12 ];
For the job interview they were perhaps hoping for:
char *mycpy( char *s, char *t )
{
while ( *s++ = *t++ )
{
;
}
return s;
}
I wouldn't use strncpy for this at all. At least if I understand what you're trying to do, I'd probably do something like this:
char *duplicate(char *input, size_t max_len) {
// compute the size of the result -- the lesser of the specified maximum
// and the length of the input string.
size_t len = min(max_len, strlen(input));
// allocate space for the result (including NUL terminator).
char *buffer = malloc(len+1);
if (buffer) {
// if the allocation succeeded, copy the specified number of
// characters to the destination.
memcpy(buffer, input, len);
// and NUL terminate the result.
buffer[len] = '\0';
}
// if we copied the string, return it; otherwise, return the null pointer
// to indicate failure.
return buffer;
}
Firstly, for strncpy, "No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num."
We use memcpy() because strncpy() checks each byte for 0 on every copy. We already know the length of the string, memcpy() does it faster.
First calculate the length of the string, then decide on what to allocate and copy
int max = 5; // No more than 5 characters
int len = strlen(string); // Get length of string
int to_allocate = (len > max ? max : len); // If len > max, it'll return max. If len <= max, it'll return len. So the variable will be bounded within 0...max, whichever is smaller
char *str = malloc(to_allocate + 1); // Only allocate as much as we need to
if (!str) { // handle bad allocation here }
memcpy(str,string,to_allocate); // We don't need any if's, just do the copy. memcpy is faster, since we already have done strlen() we don't need strncpy's overhead
str[to_allocate] = 0; // Make sure there's a null terminator
You must have storage space somewhere for the contents of your string copy. There is no magical way to make a copy of something, that doesn't require additional storage.
This however can be on the stack, as apposed to the heap, using a variable-length array.
strlen and strcpy can be used to accomplish this:
void foo(const char *input_str)
{
char temp[strlen(input_str) + 1];
strcpy(temp, str);
/* ... */
}
If your platform does not support VLAs, you must use heap memory. The strdup function is usually available. If it is not, it can be replicated easily with malloc. You must remember to free this memory when you are finished with it.
void foo(const char *input_str)
{
char *temp = strdup(input_str);
/* ... */
free(temp);
}
or
void foo(const char *input_str)
{
char *temp = malloc(strlen(input_str) + 1);
strcpy(temp, input_str);
/* ... */
free(temp);
}
If your platform does not support VLAs, and you really can not use the heap for some reason, the only option left is a buffer of a predetermined maximum length. This is a special case, and should be avoided, if possible, as it creates additional limitations you must keep track of.
#define MAX_FOO_BUFSZ 255
void foo(const char *input_str)
{
char buffer[MAX_FOO_BUFSZ + 1] = { 0 };
strncpy(buffer, input_str, MAX_FOO_BUFSZ);
/* ... */
}
You can also use strdup function (it is POSIX but it is supported by most implementations)
char *foo(const char *input_str)
{
char *temp = strdup(input_str);
if(temp)
{
// do some stuff
}
return temp;
}
Remember to free the allocated memory when not needed.
You could use strdup() to return a copy of a C-string, as in:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
stringB = strdup(stringA);
/* ... */
free(stringB);
stringB = NULL;
You could also use strcpy(), but you need to allocate space first, which isn't hard to do but can lead to an overflow error, if not done correctly:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strcpy( stringB, stringA );
/* ... */
free(stringB);
stringB = NULL;
If you cannot use strdup(), I would recommend the use of strncpy() instead of strcpy(). The strncpy() function copies up to — and only up to — n bytes, which helps avoid overflow errors. If strlen(stringA) + 1 > n, however, you would need to terminate stringB, yourself. But, generally, you'll know what sizes you need for things:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strncpy( stringB, stringA, strlen(stringA) + 1 );
/* ... */
free(stringB);
stringB = NULL;
I think strdup() is cleaner, myself, so I try to use it where working with strings exclusively. I don't know if there are serious downsides to the POSIX/non-POSIX approach, performance-wise, but I am not a C or C++ expert.
Note that I cast the result of malloc() to char *. This is because your question is tagged as a c++ question. In C++, it is required to cast the result from malloc(). In C, however, you would not cast this.
EDIT
There you go, there's one complication: strdup() is not in C or C++. So use strcpy() or strncp() with a pre-sized array or a malloc-ed pointer. It's a good habit to use strncp() instead of strcpy(), wherever you might use that function. It will help reduce the potential for errors.
If I just initialize stringB as char *stringB[23], because I know I'll never have a string longer than 22 characters (and allowing for the null terminator), is that the right way?
Almost. In C, if you know for sure that the string will never be too long:
char stringB[MAX+1];
assert(strlen(stringA) <= MAX));
strcpy(stringB, stringA);
or, if there's a possibility that the string might be too long:
char stringB[MAX+1];
strncpy(stringB, stringA, MAX+1);
if (stringB[MAX] != '\0') {
// ERROR: stringA was too long.
stringB[MAX] = '\0'; // if you want to use the truncated string
}
In C++, you should use std::string, unless you've proved that the overhead is prohibitive. Many implementations have a "short string optimisation", which will avoid dynamic allocation for short strings; in that case, there will be little or no overhead over using a C-style array. Access to individual characters is just as convenient as with a C-style array; in both cases, s[i] gives the character at position i as an lvalue. Copying becomes stringB = stringA; with no danger of undefined behaviour.
If you really do find that std::string is unusable, consider std::array<char,MAX+1>: a copyable class containing a fixed-size array.
If stringB is checked for equality with other C-strings, will the extra space affect anything?
If you use strcmp, then it will stop at the end of the shortest string, and will not be affected by the extra space.