按字母顺序排序单词 C

3

我的练习是对1D字符数组中的单词进行排序。 我的代码几乎可以工作,但它总是跳过最后一个单词的最后一个字符。 这是我的代码。 我添加了一些注释以使其有些可读性。 我知道这不是很好的代码,但我刚刚开始学习编程。

int main(void) {
    char input[] = "If you are working on something that you really care about you dont have to be pushed The vision pulls you Steve Jobs";
    sort_alphabetically(input);
    printf("%s", input);
}

int sort_alphabetically(char tab[]) {
    int j = 0, k = 0, i = 0, g = 0, f = 0, l = 0;
    char tmp[1001];
    char tmp2[501][1001];

    while (tab[i] == ' ')  // skipping leading whitespaces
        i++;

    for (j = i; tab[j] != '\0'; j++) {
        if (tab[j] != ' ' && tab[j + 1] != '\0')
            k++;             // counting word length
        else if (tab[j] == ' ' || tab[j + 1] == '\0' || tab[j + 1] == '\0') {
            // copying word t0 2d array
            for (g = k; g > 0; g--) {
                tmp[l] = tab[j - g];
                l++;
            }
            tmp[l] = 0;
            strcpy(tmp2[f], tmp);  // copying
            f++;  //words ++ in  tmp2
            k = 0;  
            l = 0;  
            tmp[0] = 0;  
        }
    }
    tab[0] = 0;
    tmp[0] = 0;

    for (j = 0; j < f; j++) {    
       for (i = 0; i < f - 1; i++) {
           if (strcmp(tmp2[i], tmp2[i + 1]) > 0) {  //sorting words in alphabeticall order
               strcpy(tmp, tmp2[i]);   
               strcpy(tmp2[i], tmp2[i + 1]);   
               strcpy(tmp2[i + 1], tmp);
           }
       }
    }   

    for (i = 0; i < f; i++) {
        strcat(tab, tmp2[i]);    // copying to tab 
        strcat(tab, " ");   //adding spaces after each word
    }
    // removing whitespaces
    for (i = 0; tab[i] == ' ' || tab[i] == '\t'; i++);

    for (j = 0; tab[i]; i++) {
        tab[j++] = tab[i];
    }
    tab[j] = '\0';
}
;

运行这段代码后,它会将最后一个单词(Jobs)中的s 切掉。如果有人能帮我理清这个问题就太好了。

4
您的排序函数表示会返回int类型,但实际上却没有返回。 - Retired Ninja
1
"但我刚刚开始学习编程。", "如果有人能帮助我", 和 @Retired Ninja 暗示你正在犯一个常见的学习错误:没有首先使用自动化编译器并启用警告。节省时间,大量时间,并完全启用编译器警告。更快的反馈在此发布。" - chux - Reinstate Monica
3个回答

3
问题在于你处理空字节和空格字符的方式不同。在处理空格字符时,你实际上是在拷贝字符串时包含了空格字符。但在处理空字节时,你实际上是在空字节之前进行操作的。这会导致一个一位偏差错误。你需要修改代码以避免对空字节和空格字符的不同处理:
for (j = i; tab[j] != '\0'; j++) {
    //In the space case, you are on the space, but in the \0 case
    //you were one before it.
    //Changed this if statement so that you always copy the string
    //when you're at the last character.
    if (tab[j + 1] == ' ' || tab[j + 1] == '\0') {

        //k is a length, but we're using it as an index
        //so we will need to adjust by one
        for (g = k; g > 0; g--) {
            tmp[l] = tab[j - g + 1];
            l++;
        }
    }
    else
    {
       k++;
    }
}

我通过添加打印语句来显示每个循环中tab[j]k的值,从而解决了这个问题。观察程序的执行过程(无论是使用打印语句还是调试器)通常是诊断此类问题的最佳方式。


1
你遇到的问题是在将字符复制到tmp缓冲区时,当输入(tab)字符串结束时,即当tab[j + 1] == '\0'为真时。在这种情况下,你没有复制最后一个数据到这个for循环中:
    for (g = k; g > 0; g--) {
        tmp[l] = tab[j - g];
        l++;
    }

为了解决这个问题,只需将循环的“条件”更改为包括当g为零时,并在遇到空格字符时跳过此“迭代”即可。
    for (g = k; g >= 0; g--) { // Make sure to include any 'last' character
        if (tab[j - g] != ' ') { // ... but skip if this is a space
            tmp[l] = tab[j - g];
            l++;
        }
    }

请注意,这行代码中存在多余的测试:
    else if (tab[j] == ' ' || tab[j + 1] == '\0' || tab[j + 1] == '\0') {

这段代码可以省略第三个测试(与第二个测试相同),因此可以这样写:

    else if (tab[j] == ' ' || tab[j + 1] == '\0') {

现在它取到了最后一个字符,但打印出的是 JobsSteve 而不是 Jobs Steve - Cnewbiec
也许可以尝试最新的编辑。但是Korosia给出的答案实际上更好! - Adrian Mole

1
< p > 注意: 大多数其他回答者已经指出了您代码中的主要错误,但其中还存在一些较小的错误和一些简化。

在对tab执行strcat之前,我们应该执行tab[0] = 0,以便初始的strcat可以正确工作。

在复制单词的那个strcat之后执行strcat(tab," ")会超出tab的末尾,因此属于未定义的行为。这还需要一个不必要的清理循环来删除本来就不该存在的额外空格。

最初的“拆分为单词”的循环可以[大大地]简化。

有一些标准的冒泡排序加速技巧。

我知道你刚开始学习[有些学校甚至提倡使用i, j等],但最好使用一些[更]具有描述性的名称。

无论如何,以下是一个稍微重构过的版本:

#include <stdio.h>
#include <string.h>

int opt_dbg;

#define dbg(_fmt...) \
    if (opt_dbg) \
        printf(_fmt)

void
sort_alphabetically(char tab[])
{
    char tmp[1001];
    char words[501][1001];
    char *src;
    char *dst;
    char *beg;
    int chr;
    int wordidx;
    int wordcnt;

    wordidx = 0;
    dst = words[wordidx];
    beg = dst;

    // split up string into individual words
    src = tab;
    for (chr = *src++;  chr != 0;  chr = *src++) {
        switch (chr) {
        case ' ':
        case '\t':
            // wait until we've seen a non-white char before we start a new
            // word
            if (dst <= beg)
                break;

            // finish prior word
            *dst = 0;

            // point to start of next word
            dst = words[++wordidx];
            beg = dst;
            break;

        default:
            *dst++ = chr;
            break;
        }
    }

    // finish last word
    *dst = 0;

    // get number of words
    wordcnt = wordidx + 1;

    if (opt_dbg) {
        for (wordidx = 0; wordidx < wordcnt; ++wordidx)
            dbg("SPLIT: '%s'\n",words[wordidx]);
    }

    // in bubble sort, after a given pass, the _last_ element is guaranteed to
    // be the largest, so we don't need to examine it again
    for (int passlim = wordcnt - 1;  passlim >= 1;  --passlim) {
        int swapflg = 0;

        // sorting words in alphabetical order
        for (wordidx = 0;  wordidx < passlim;  ++wordidx) {
            char *lhs = words[wordidx];
            char *rhs = words[wordidx + 1];

            if (strcmp(lhs,rhs) > 0) {
                dbg("SWAP/%d: '%s' '%s'\n",passlim,lhs,rhs);
                strcpy(tmp,lhs);
                strcpy(lhs,rhs);
                strcpy(rhs,tmp);
                swapflg = 1;
            }
        }

        // if nothing got swapped, we can stop early (i.e. everything is in
        // sort)
        if (! swapflg)
            break;
    }

    // clear out destination so [first] strcat will work
    tab[0] = 0;

    // copy back words into original string
    // adding the space as a _prefix_ before a word eliminates the need for a
    // cleanup to remove the last space
    for (wordidx = 0;  wordidx < wordcnt;  ++wordidx) {
        dbg("SORTED: '%s'\n",words[wordidx]);

        // adding spaces before each word
        if (wordidx > 0)
            strcat(tab, " ");

        // copying to tab
        strcat(tab,words[wordidx]);
    }
}

int
main(int argc,char **argv)
{
    char input[] = "If you  are  working on something that you really care"
        " about you dont have to be  pushed The vision pulls you Steve Jobs";

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        char *cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'd':
            opt_dbg = ! opt_dbg;
            break;
        }
    }

    sort_alphabetically(input);
    printf("%s\n", input);

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接