#include <stdio.h>
int main()
{
char * str[ ]={"C program", "Basic", "Foxbase ", "Fortran", "Pascal"};
int i,j;
char * temp;
int k;
for(i=0;i<4;i )
{
k=i;
for(j=i 1;j<5;j )
if(str[i] < str[j]) k=j;
temp=str[i]; str[i] = str[k]; str[k] = temp;
}
for(i=0;i<5;i )
printf("%s\n",str[i]);
return 0;
}
I wanna sort the strings given above by the order of letter(ASCII), but I just couldn't do it, I already know that the wrong part of this code is the
if(str[i] < str[j]) k=j;
And I tried to fix it many times, just doesn't work out. I already tried: *str[i] < *str[j] (didn't work, which I think is reasonable?)
Btw, using string.h is not allowed, how can I make everything right here?
CodePudding user response:
As arising from the comments to the question you are not allowed to use any library functions – thus you need to compare those strings manually (note that you cannot just compare the pointers, these might be arbitrary addresses, you need to compare what the strings point to!) – and as you even don't seem to be allowed to write a separate function you need to inline this code as well.
In general string comparison might look as follows (here still as a function):
int cmp(char const* x, char const* y)
{
for(; *x && *y; x, y)
{
if(*x != *y)
// first position where the strings differ:
// x < y lexicographically if *x < *y, thus *x - *y < 0
// x > y analogously, so:
return *x - *y;
// this gives you the equivalence: x # y <=> cmp(x, y) # 0
// with # being any comparison operator
}
#if 0
if(*x)
return 1; // x is longer, thus x > y
if(*y)
return -1; // y is longer, thus x < y
return 0; // both equal
#else
// actually, as the null terminator is smaller than any other character
// anyway, we still can simply:
return *x - *y;
#endif
}
Edit: An even simpler solution (thanks @Lundin for the hint) just iterates as long as the strings yet can be equal:
while(*x && *x == *y) // covers *y being 0, too!
{
x; y;
}
return *x - *y;
Side note: There's an issue with the comparison if your strings include values in the upper half of the character range (from 128 up to 255 inclusive; not an issue with your example): It is unspecified if raw char
is signed or unsigned, if you want to have portable/stable behaviour on all platforms and compilers you might want to cast to unsigned char
at any comparison (above and below):
return static_cast<unsigned char>(*x) - static_cast<unsigned char>(*y);
Using such a function is, in general, the solution to prefer. Maybe you ask once more if you are allowed to write a new function after all!
Otherwise in your case you could reduce the code for testing on being smaller only, so:
char const* cur = str[j];
char const* min = str[k];
while(*cur && *cur == *min)
{
cur; min;
}
if(*cur < *min)
{
// cur is lexicographically smaller or shorter than min!
// -> found a new minimum
k = j;
}
CodePudding user response:
Rather than compare pointers with
if(str[i] < str[j]) // Compare pointers
code need to compare the strings refenced by those pointers.
if (strcmp(str[i], str[j])) // Compare strings
As OP is obliged to not use strcmp()
, make your own by comparing the strings, one character at a time (as unsigned char
) for equality (and not a null character). Report zero when the same or a negative or positive corresponding to the sign of the difference.
// Use const to allow for pointers to const strings.
int my_strcmp(const char *x, const char *y) {
// Convert to unsigned char * as `strcmp()` compares "as if"
// the characters were all unsigned.
const unsigned char *ux = (const unsigned char*) x;
const unsigned char *uy = (const unsigned char*) y;
// Test for equality and null character.
// I like to place the more likely to fail one first.
while ((*ux == *uy) && *ux) {
ux ;
uy ;
}
// On rare machines, using `return *ux - *uy` may overflow.
// To avoid overflow, use 2 tests.
// Good compilers see this idiom and emit efferent code.
return (*ux > *uy) - (*ux < *uy);
}