Aside from errors mentioned by others, you are supposed to compare the characters as unsigned char. This gets important once you go beyond ASCII-7, your results will be wrong if you don't.
The following is my own (tested) implementation (from my original work on PDCLib, which is CC0 licensed).
int strncmp( const char * s1, const char * s2, size_t n )
{
while ( n && *s1 && ( *s1 == *s2 ) )
{
++s1;
++s2;
--n;
}
if ( n == 0 )
{
return 0;
}
else
{
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
}
Answer from DevSolar on Stack OverflowVideos
Aside from errors mentioned by others, you are supposed to compare the characters as unsigned char. This gets important once you go beyond ASCII-7, your results will be wrong if you don't.
The following is my own (tested) implementation (from my original work on PDCLib, which is CC0 licensed).
int strncmp( const char * s1, const char * s2, size_t n )
{
while ( n && *s1 && ( *s1 == *s2 ) )
{
++s1;
++s2;
--n;
}
if ( n == 0 )
{
return 0;
}
else
{
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
}
control may reach end of non-void function
The last iteration of a non-void function must be a return. (your function return an int)
In some cases your code will not use a return. You need one so try to find where ;).
What does strncmp actually do?
strncmp compares the first two characters in the strings. (When comparing characters, it uses their values as unsigned char, even though they are passed via pointers to char.) If the characters differ or either is a null character:
- If the character from the first string is greater than the character from the second,
strncmpreturns a positive value. - If the first is less than the second,
strncmpreturns a negative value. - Otherwise (the characters are both null characters),
strncmpreturns zero.
If the characters did not differ and neither was a null character, strncmp goes on to compare the following characters in the same way, until n pairs have been compared. If no difference has been found after n pairs have been compared, strncmp returns zero.
Some implementations of strncmp may return the signed difference between the two characters that differed, but this is not required by the C standard. strncmp may simply return +1 and −1 for “greater than” and “less than” or may use other positive and negative values.
strncmp(s1, s2, n) compares up to n characters from the strings pointed to by s1 and s2. It stops if it finds a difference and returns a negative value if the character from s1, converted to an unsigned char is less than the corresponding character from s2 (also converted to an unsigned char) and a positive value it is is greater. Subtracting the values of the differing characters is a handy way to compute a return value with the correct sign.
If no difference was found before the end of both strings or n characters have been processed, whichever comes first, it returns 0.
Your code has some small issues:
- the pointer arguments should be declared with type
const char *andnwith typesize_t. - similarly,
ishould be defined as asize_t, defining it as anintforces you to use a cast in the comparison and will cause undefined behavior for strings with an identical prefix longer thanINT_MAXand a large enoughnargument. - you should not dereference
s1[i]nors2[i]ifnhas reached0, so the test onnshould be performed first. - the difference should be computed as
diff = (unsigned char)s1[i] - (unsigned char)s2[i]; - note also that on some very exotic platforms, where
sizeof(char) == sizeof(int), the subtraction cannot be used as it may wrap around and produce incorrect results. - it is preferable to not use names reserved for standard functions for your own versions and it may cause clashes with the compiler's intrinsics.
Here is a modified version:
#include <stdio.h>
int my_strncmp(const char *s1, const char *s2, size_t n) {
for (size_t i = 0; i < n; i++) {
int diff = (unsigned char)s1[i] - (unsigned char)s2[i];
if (diff != 0 || s1[i] == '\0')
return diff;
}
return 0;
}
int main() {
char s11[] = "abcs";
char s12[] = "zzfs";
size_t n = 3;
printf(" strncmp() -> %d\n", strncmp(s11, s12, n));
printf("my_strncmp() -> %d\n", my_strncmp(s11, s12, n));
return 0;
}
The output values may differ but should have the same sign or should both be null.
I think you've misinterpreted the definition of strncat, which says,
Appends the first
numcharacters of source to destination, plus a terminating null-character. If the length of the C string in source is less thannum, only the content up to the terminating null-character is copied.
n is the maximum number of characters in source you you want to copy, and bfsize doesn't exist in the standard version of strncat.
char destination[256];
strpy(destination, "foo");
strncat(destination, "bar", 2);
// expect destination should now contain "fooba" !
It's good of you to write a custom version with an extra parameter to make it safe, but that's not what the question asked for.
See also Manual Reference Pages - Strn (3) (e.g. Strncat instead of strncat); or, the Microsoft versions of the 'safe' functions have _l as a suffix.
I'm not sure that returning null and doing no copy is the standard way to avoid buffer overflow.
In your custom_strncmp method, I'm not sure what correct behaviour should be if you call
strncmp("foo", "foo", 10);
Your function might return 0 or non-zero, or crash, depending on what's after the end of the string.
You could perhaps write it more elegantly as a for loop:
for ( ; n--; ++s, ++t) {
if(*s != *t) {
return *s - *t;
}
}
In custom_strncat you don't handle the condition where n > strlen(t).
Your parameters could (should) be better named, e.g. source and destination. Parameter names are important (even more important than good names for local variables) because they may be the only documentation about how the function should be called.
Years later, but for completeness ... custom_strncpy above is not compatible with standard strncpy.
- It writes
n+1characters into destination (onlynis correct). - It reads past
\0of source string. - It does not
\0-pad destination string if source is smaller. - it always
\0terminates. (strncpy will not in case strlen(source) >=s).