-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.

12
  • 1
    if #include <string.h> is forbidden, the best you can do is to write strcmp() yourself. Then, you can use it with qsort() in <stdlib.h>. Commented Dec 15, 2022 at 9:15
  • I can only edit this line I think...it's a fill-in-blank question so I don't have much freeedom here Commented Dec 15, 2022 at 9:19
  • 1
    These are string literals, so you should have an array of poiner to const char: const char *str[] =... Commented Dec 15, 2022 at 9:28
  • 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 codegolf.stackexchange.com. Commented Dec 15, 2022 at 9:36
  • 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. Commented Dec 15, 2022 at 13:28

2 Answers 2

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;
}
Sign up to request clarification or add additional context in comments.

7 Comments

Or we could KISS...: int cmp(char const* x, char const* y) { for(; *x && (*x == *y); ++x, ++y){} return *x - *y; }
Actually just using 1 iterator would be the KISS version. And slightly more efficient godbolt.org/z/TfTGazYoq
@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-ReinstateMonica Just to be precise: When one of is negative, the other one positive... Compare 0xfe < 0xff vs. -2 < -1...
@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).
|
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);
}

1 Comment

Never thought of writing that on my own, this is pretty cool lol.Thx for reminding me of that!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.