-2
#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?

EDIT: sorry I posted this question that is silly, I didn't know that even if I couldn't use string.h, I can also use stdlib.h to use strcmp function, I was confused at that time but now everything is clear. Thanks for you guys spending time here, I appreciate it, and sorry again for asking this silly question.

Katono
  • 28
  • 4
  • 1
    if `#include ` is forbidden, the best you can do is to write `strcmp()` yourself. Then, you can use it with [`qsort()`](https://man7.org/linux/man-pages/man3/qsort.3p.html) in ``. – mouviciel Dec 15 '22 at 09:15
  • I can only edit this line I think...it's a fill-in-blank question so I don't have much freeedom here – Katono Dec 15 '22 at 09:19
  • Then forget about `qsort()`, and code `srtcmp()` within that single line that you can edit. This is not that difficult once you fully understand how strings work in C. – mouviciel Dec 15 '22 at 09:22
  • Additionally, even if above *did* work, then you'd need to compare `str[j] < str[k]` – you want to find a new minimum, don't you? – Aconcagua Dec 15 '22 at 09:23
  • 1
    These are string literals, so you should have an array of poiner to const char: `const char *str[] =...` – hyde Dec 15 '22 at 09:28
  • Even if you fix the comparison, the sort is wrong. `if(str[i] < str[j]) k=j;` should be comparing `str[j]` to `str[k]` so that `k` eventually points to the minimum. – Paul Hankin Dec 15 '22 at 09:30
  • 1
    @Katono "I can only edit this line" You can edit any line you want. This isn't a puzzle site for artificial programming challenges, this is a site for practical programming using best practices. Artificial programming puzzles belong on https://codegolf.stackexchange.com/. – Lundin Dec 15 '22 at 09:36
  • @Lundin - I would be glad to know what makes you think this is a code golf instead of homework and the requirement would be artificial. By the way thank you for the better duplicate. – mouviciel Dec 15 '22 at 12:05
  • 1
    @mouviciel In the real world, the lead dev won't hand you this task and say "you may only change this line and you are not allowed to use string.h". It isn't code golf but it's an artificial programming puzzle. – Lundin Dec 15 '22 at 13:28
  • To me, this artificial programming puzzle looks like homework and the lead dev is a teacher. I agree that in the real world, `` is not forbidden. – mouviciel Dec 15 '22 at 13:37
  • Thx guys, I was confused because there's no string.h but now I found out that stdlib.h can also use strcmp function... – Katono Jan 10 '23 at 09:51
  • qsort is a new thing to me. I would love to try it. Thx – Katono Mar 06 '23 at 12:27

2 Answers2

2

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 – which makes a difference on comparing characters not residing in the same half of the range of char (200 - 100 = 100 > 0 <-> -56 - 100 = -156 < 0). You can achieve more consistent behaviour over different platforms if you cast to unsigned char at any difference or 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;
}
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • 1
    Or we could [KISS](https://en.wikipedia.org/wiki/KISS_principle)...: `int cmp(char const* x, char const* y) { for(; *x && (*x == *y); ++x, ++y){} return *x - *y; }` – Lundin Dec 15 '22 at 10:19
  • Actually just using 1 iterator would be the KISS version. And slightly more efficient https://godbolt.org/z/TfTGazYoq – Lundin Dec 15 '22 at 10:53
  • @Lundin `return *x - *y;` is a problem when `*x, *y` are negative. `strcmp()` compares _strings_ as if they were `unsigned char[]`. Not an issue for OP's test case, but for correct `strcmp()` like code, access the strings as if `const unsigned char[]`. – chux - Reinstate Monica Dec 15 '22 at 10:54
  • @chux-ReinstateMonica Just to be precise: When one of is negative, the other one positive... Compare `0xfe < 0xff` vs. `-2 < -1`... – Aconcagua Dec 15 '22 at 12:16
  • @Lundin About KISS: This second variant doesn't appear simpler to me – replacing the simple `*x`/`*y` with all these index operators in contrast even looks more complicated to me – and from point of efficiency any index operator hides yet another addition, though I didn't go through the assembly (yet?) to see if the compiler could optimise one or the other variant better (interestingly enough it's not the same at least, which a short glance at reveals). – Aconcagua Dec 15 '22 at 12:39
  • Pedantic: "if you want to have portable/stable behaviour on all platforms" --> `while(*cur && *cur == *min)` needs to be done with `unsigned char` access to not error when the character is -0 (or a trap) for those pesky, soon to be eliminated, non-2's complement as only `+0` is a _null character_. IAC, `` specs: "For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value)." – chux - Reinstate Monica Dec 15 '22 at 18:03
  • The KISS thought is pretty amazing and beautiful, thx for helping me! – Katono Mar 06 '23 at 12:26
0

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 efficient code.
  return (*ux > *uy) - (*ux < *uy);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Never thought of writing that on my own, this is pretty cool lol.Thx for reminding me of that! – Katono Mar 06 '23 at 12:24