按长度对 argv 中的单词进行排序

man*_*ist 7 c sorting string command-line-arguments

我正在尝试使用 C 语言从命令行读取单词argv,然后根据它们的长度按降序对它们进行排序。然而,我的排序算法产生了意想不到的输出。

我使用的代码如下:

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

int main(int argc, char *argv[]) {

    for (int i = 1; i < argc - 1; i++) {
        for (int j = 1; j < argc - i - 1; j++) {
            if (strlen(argv[j]) < strlen(argv[j + 1])) {
                char temp_word[20];
                strcpy(temp_word, argv[j]);
                strcpy(argv[j], argv[j + 1]);
                strcpy(argv[j + 1], temp_word);
            }
        }
    }

    puts("\n");
    for (int i = 1; i < argc; i++) {
        printf("%s ", argv[i]);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc test.c -o test
./test I put this words


puwordI wordI I  % 
Run Code Online (Sandbox Code Playgroud)

不幸的是,输出已损坏。我怀疑我的排序逻辑或处理命令行参数的方式可能存在问题。有人可以检查我的代码并提供有关如何按长度正确排序单词的指导吗?

Adr*_*ica 4

您的代码有两个问题。首先,您尝试交换数组中字符串的内容argv:这不起作用,因为分配要交换的两个字符串中较短的字符串的缓冲区将不足以容纳较长的“替换” 并且由于缓冲区溢出将导致未定义的行为。相反,只需交换实际的指针即可。

其次,您没有测试整个数组;- 1从两个循环的极限中取出for

这是代码的更正版本:

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

int main(int argc, char* argv[])
{
    for (int i = 1; i < argc; i++) { // Use "argc" (not argc - 1)
        for (int j = 1; j < argc - i; j++) { // Similarly, no -1 here!
            if (strlen(argv[j]) < strlen(argv[j + 1])) {
                char* temp_word = argv[j];
                argv[j] = argv[j + 1];    // Just swap the pointers,
                argv[j + 1] = temp_word;  // not the string contents
            }
        }
    }

    puts("\n");
    for (int i = 1; i < argc; i++) {
        printf("%s ", argv[i]);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:根据关于修改元素argv(如上面的代码)是否安全(或者是否会导致未定义的行为)的评论,我在下面提供了一个版本,它首先制作数组的副本,然后使用它:

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

int main(int argc, char* argv[])
{
    // First, make a copy of the argv array ...
    char** argvCopy = malloc((size_t)argc * sizeof(char*));
    memcpy(argvCopy, argv, (size_t)argc * sizeof(char*));
    // Now sort that copy ...
    for (int i = 1; i < argc; i++) {
        for (int j = 1; j < argc - i; j++) {
            if (strlen(argvCopy[j]) < strlen(argvCopy[j + 1])) {
                char* temp_word;
                temp_word = argvCopy[j];
                argvCopy[j] = argvCopy[j + 1];
                argvCopy[j + 1] = temp_word;
            }
        }
    }

    puts("\n");
    for (int i = 1; i < argc; i++) {
        printf("%s ", argvCopy[i]);
    }

    free(argvCopy); // Don't forget to free the copy.
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅此处的讨论:Is argv[n] writable?