如何按字母顺序排列字符数组中的字符串?

How do would I alphabetize the strings in my character array?

我编写了一个程序来计算用户输入的字符串中字母和单词的出现次数。我现在已经成功地让其中的大部分工作,但是,我还必须按字母顺序排列存储在我的指针数组中的单词。我看到了一个函数 void sortstring() ,它应该只是这个,但它似乎根本不起作用。我该怎么做?

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


void findLetters(char *ptr);
void findWords(char *point);
void sort_string(char *p);

int main()
{
    char textStream[100]; //up to 98 characters and '\n\ and '[=10=]'

    printf("enter some text\n");
    if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
    {
        findLetters(textStream);
        findWords(textStream);
        sort_string(textStream);
    }
    else
    {
        printf("fgets failed\n");
    }

    return 0;
}

void findLetters(char *ptr) //find occurences of all letters
{
    int upLetters[26];
    int loLetters[26];
    int i;
    int index;

    for (i = 0; i < 26; i++) // set array to all zero
    {
        upLetters[i] = 0;
        loLetters[i] = 0;
    }
    i = 0;
    while (ptr[i] != '[=10=]') // loop until prt[i] is '[=10=]'
    {
        if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
        {
            index = ptr[i] - 'A';// subtract 'A' to get index 0-25
            upLetters[index]++;//add one
        }

        if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
        {
            index = ptr[i] - 'a';//subtract 'a' to get index 0-25
            loLetters[index]++;//add one
        }
        i++;//next character in ptr
    }
    printf("Number of Occurrences of Uppercase letters\n\n");
    for (i = 0; i < 26; i++)//loop through 0 to 25
    {
        if (upLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
            // add 'A' to go from an index back to a character
        }
    }
    printf("\n");
    printf("Number of Occurrences of Lowercase letters\n\n");
    for (i = 0; i < 26; i++)
    {
        if (loLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
            // add 'a' to go back from an index to a character
        }
    }
    printf("\n");
}

void findWords(char *point)
{
    int i = 0;
    int k = 0;
    int count = 0;
    int j = 0;
    int space = 0;
    int c = 0;
    int len = strlen(point);
    char copy[50][100];
    char* delim = "{ } . , ( ) ";
    char **word;
    char *newpoint;
    char *newerpoint;
    char *token;
    int occur[50]; // will store number of occurances of each word

    for (; i < 50; i++) //sets all indexes to 0
    {
        occur[i] = 0;
    }

    for (i = 0; i < len; i++) //counts # of spaces between words
    {
        if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
        {
            space++;
        }
    }
    word = malloc(sizeof(char*)*(space+1)); //allocates memory to array according to number of words
    newpoint = malloc(strlen(point)+1);
    strcpy(newpoint, point);
    newerpoint = malloc(strlen(point) + 1);
    strcpy(newerpoint, point);
    token = strtok(newpoint, delim);

    for (k; k <= space && token != NULL; k++)
    {
        word[k] = malloc(strlen(token) + 1);
        strcpy(word[k], token);
        token = strtok(NULL, delim);
        printf("%s\n", word[k]);
    }

    for (k = 0; k <= space; k++)
    {
        free(word[k]);
    }
}

void sort_string(char *p)
    {
        int c, d = 0, length;
        char *pointer, *result, ch;

        length = strlen(p);
        result = (char*)malloc(length + 1);

        pointer = p;

        for (ch = 'a'; ch <= 'z'; ch++)
        {
            for (c = 0; c < length; c++)
            {
                if (pointer == ch)
                {
                    *(result + d) = *pointer;
                    d++;
                }
                pointer++;
            }
            pointer = p;
        }
        *(result + d) = '[=10=]';

        strcpy(p, result);
        free(result);
    }

编辑版本:

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

void findLetters(char *ptr);
void findWords(char *point);
int compare_str (const void *a, const void *b);


int main (void)
{
    char textStream[100] = {0};     //up to 98 characters and '\n\ and '[=11=]'
    typedef unsigned int size_t;
    size_t len = 0;
    printf ("enter some text\n");
    if (fgets (textStream, sizeof textStream, stdin)) //input up to 99 characters
    {
        len = strlen (textStream);
        textStream[--len] = 0;      // strip newline from end of textStream

        findLetters (textStream);
        findWords (textStream);
    }
    else
    {
        printf("fgets failed\n");
    }

    return 0;
}

void findLetters(char *ptr) //find occurences of all letters
{
    int upLetters[26];
    int loLetters[26];
    int i;
    int index;

    for (i = 0; i < 26; i++) // set array to all zero
    {
        upLetters[i] = 0;
        loLetters[i] = 0;
    }
    i = 0;
    while (ptr[i] != '[=11=]') // loop until prt[i] is '[=11=]'
    {
        if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
        {
            index = ptr[i] - 'A';// subtract 'A' to get index 0-25
            upLetters[index]++;//add one
        }

        if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
        {
            index = ptr[i] - 'a';//subtract 'a' to get index 0-25
            loLetters[index]++;//add one
        }
        i++;//next character in ptr
    }
    printf("Number of Occurrences of Uppercase letters\n\n");
    for (i = 0; i < 26; i++)//loop through 0 to 25
    {
        if (upLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
            // add 'A' to go from an index back to a character
        }
    }
    printf("\n");
    printf("Number of Occurrences of Lowercase letters\n\n");
    for (i = 0; i < 26; i++)
    {
        if (loLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
            // add 'a' to go back from an index to a character
        }
    }
    printf("\n");
}

void findWords(char *point)
{
    int i, k, count, space;
    int len = strlen (point);
    char *delim = "\n { } . , ( ) ";
    char **word = NULL;
    char *newpoint = NULL;
    char *token = NULL;

    i = k = count = space = 0;

    for (i = 0; i < len; i++) //counts # of spaces between words
        if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
            space++;

    word = malloc (sizeof *word * space + 1); //allocates memory to array according to number of words
    newpoint = malloc (strlen (point) + 1);
    strcpy (newpoint, point);
    token = strtok (newpoint, delim);

    printf ("\nSeparating and saving words in pointer array:\n\n");
    for (k = 0; token != NULL; k++)
    {
        word[k] = malloc (strlen (token) + 1);
        strcpy (word[k], token);
        token = strtok (NULL, delim);
        printf ("%s\n", word[k]);
    }

    count = k;  /* save number of string in word */

    qsort (word, count, sizeof *word, compare_str);     /* sort the array of pointers */

    printf ("\nSorted words in pointer array:\n\n");
    for (k = 0; k < count; k++)
        printf ("%s\n", word[k]);

    for (k = 0; k < count; k++)
    {
        free(word[k]);
    }
}


int compare_str (const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcmp(*ia, *ib);
}

当您开始使用它时,我想您会大吃一惊。 sort_string 函数与对指针数组 中的单词 进行排序没有任何关系,而是对数组 中的 个字符进行排序。例如:

$ ./bin/str_sort_words

Enter a string: a quick brown fox jumps over the lazy dog
  sorted words: aabcdeefghijklmnoooopqrrstuuvwxyz

相反,您需要使用 qsort 对指针数组进行排序,这样您实际上是在对单词而不是字符进行排序。要使用 qsort,您必须为其提供一个 compare 函数,以便它知道要排序的项目的大小和数量。对于指针数组,qsort 比较函数如下所示:

/* qsort C-string comparison function */
int compare_str (const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcmp(*ia, *ib);
}

那么在你的情况下,你必须在指针数组 word 所在的 findWords 函数中调用它,如下所示:

qsort (word, count, sizeof *word, compare_str);

(其中 count 相当于您的 space + 1)。现在,在我们查看答案之前,您需要在编译时启用 Warnings(您的代码不会由于 if (pointer == ch) 中的 pointer/int 不匹配而应该是 if (*pointer == ch).

但除此之外,在启用警告的情况下进行编译会指出 findWords 中的一整套问题。要启用警告,请将 -Wall -Wextra 添加到您的编译字符串中。

现在让我们看看对您的代码所做的更改。 始终初始化所有变量:

char textStream[100] = {0};     //up to 98 characters and '\n\ and '[=13=]'
size_t len = 0;

接下来,当使用 fgetsgetline 时,最好去掉尾部 newline,这样它就不会从你的琴弦上晃来晃去:

if (fgets (textStream, sizeof textStream, stdin)) //input up to 99 characters
{
    len = strlen (textStream);
    textStream[--len] = 0;      // strip newline from end of textStream
    ...

现在,更改为 findWords

void findWords(char *point)
{
    int i = 0;
    int k = 0;
    int count = 0;
    // int j = 0;
    int space = 0;
    // int c = 0;
    int len = strlen(point);
    // char copy[50][100];
    char* delim = "{ } . , ( ) ";
    char **word = NULL;
    char *newpoint = NULL;
    char *newerpoint = NULL;
    char *token = NULL;
//     int occur[50]; // will store number of occurances of each word
// 
//     for (; i < 50; i++) //sets all indexes to 0
//     {
//         occur[i] = 0;
//     }


    for (i = 0; i < len; i++) //counts # of spaces between words
    {
        if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
        {
            space++;
        }
    }
    word = malloc (sizeof *word * space + 1); //allocates memory to array according to number of words
    newpoint = malloc (strlen (point) + 1);
    strcpy (newpoint, point);
    newerpoint = malloc (strlen (point) + 1);
    strcpy (newerpoint, point);
    token = strtok (newpoint, delim);

    printf ("\nSeparating and saving words in pointer array:\n\n");
    for (k = 0; token != NULL; k++)
    {
        word[k] = malloc (strlen (token) + 1);
        strcpy (word[k], token);
        token = strtok (NULL, delim);
        printf ("%s\n", word[k]);
    }

    count = k;  /* save number of string in word */

    qsort (word, count, sizeof *word, compare_str);     /* sort the array of pointers */

    printf ("\nSorted words in pointer array:\n\n");
    for (k = 0; k < count; k++)
        printf ("%s\n", word[k]);

    for (k = 0; k < count; k++)
    {
        free(word[k]);
    }
}

编译时,应该有NO个警告:

gcc -Wall -Wextra -o yourprog yourfile.c

例子Use/Output

$ ./bin/str_find_ltr_words
enter some text
the quick brown fox jumped over a lazy dog
Number of Occurrences of Uppercase letters


Number of Occurrences of Lowercase letters

a :     2
b :     1
c :     1
d :     2
e :     3
f :     1
g :     1
h :     1
i :     1
j :     1
k :     1
l :     1
m :     1
n :     1
o :     4
p :     1
q :     1
r :     2
t :     1
u :     2
v :     1
w :     1
x :     1
y :     1
z :     1


Separating and saving words in pointer array:

the
quick
brown
fox
jumped
over
a
lazy
dog


Sorted words in pointer array:

a
brown
dog
fox
jumped
lazy
over
quick
the

最后一点。在您的 findWords 函数中有 lot 不相关的代码。我没有花时间把它去掉,因为那并不能阻止你说那种话。具有上述修改的代码会在没有警告的情况下编译。所以我会把它留给你去通过 findWords 并摆脱不需要的东西。


完整示例

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

void findLetters(char *ptr);
void findWords(char *point);
void sort_string(char *p);
int compare_str (const void *a, const void *b);


int main (void)
{
    char textStream[100] = {0};     //up to 98 characters and '\n\ and '[=18=]'
    size_t len = 0;

    printf ("enter some text\n");
    if (fgets (textStream, sizeof textStream, stdin)) //input up to 99 characters
    {
        len = strlen (textStream);
        textStream[--len] = 0;      // strip newline from end of textStream

        findLetters (textStream);
        findWords (textStream);
        sort_string (textStream);
    }
    else
    {
        printf("fgets failed\n");
    }

    return 0;
}

void findLetters(char *ptr) //find occurences of all letters
{
    int upLetters[26];
    int loLetters[26];
    int i;
    int index;

    for (i = 0; i < 26; i++) // set array to all zero
    {
        upLetters[i] = 0;
        loLetters[i] = 0;
    }
    i = 0;
    while (ptr[i] != '[=18=]') // loop until prt[i] is '[=18=]'
    {
        if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
        {
            index = ptr[i] - 'A';// subtract 'A' to get index 0-25
            upLetters[index]++;//add one
        }

        if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
        {
            index = ptr[i] - 'a';//subtract 'a' to get index 0-25
            loLetters[index]++;//add one
        }
        i++;//next character in ptr
    }
    printf("Number of Occurrences of Uppercase letters\n\n");
    for (i = 0; i < 26; i++)//loop through 0 to 25
    {
        if (upLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
            // add 'A' to go from an index back to a character
        }
    }
    printf("\n");
    printf("Number of Occurrences of Lowercase letters\n\n");
    for (i = 0; i < 26; i++)
    {
        if (loLetters[i] > 0)
        {
            printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
            // add 'a' to go back from an index to a character
        }
    }
    printf("\n");
}

void findWords(char *point)
{
    int i, k, count, space;
    int len = strlen (point);
    char *delim = "{ } . , ( ) \n";
    char **word = NULL;
    char *newpoint = NULL;
    char *token = NULL;

    i = k = count = space = 0;

    for (i = 0; i < len; i++) //counts # of spaces between words
        if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
            space++;

    word = malloc (sizeof *word * space + 1); //allocates memory to array according to number of words
    newpoint = malloc (strlen (point) + 1);
    strcpy (newpoint, point);
    token = strtok (newpoint, delim);

    printf ("\nSeparating and saving words in pointer array:\n\n");
    for (k = 0; token != NULL; k++)
    {
        word[k] = malloc (strlen (token) + 1);
        strcpy (word[k], token);
        token = strtok (NULL, delim);
        printf ("%s\n", word[k]);
    }

    count = k;  /* save number of string in word */

    qsort (word, count, sizeof *word, compare_str);     /* sort the array of pointers */

    printf ("\nSorted words in pointer array:\n\n");
    for (k = 0; k < count; k++)
        printf ("%s\n", word[k]);

    for (k = 0; k < count; k++)
    {
        free(word[k]);
    }
}

void sort_string(char *p)
{
    int c, d = 0, length;
    char *pointer, *result, ch;

    length = strlen(p);
    result = (char*)malloc(length + 1);

    pointer = p;

    for (ch = 'a'; ch <= 'z'; ch++)
    {
        for (c = 0; c < length; c++)
        {
            if (*pointer == ch)
            {
                *(result + d) = *pointer;
                d++;
            }
            pointer++;
        }
        pointer = p;
    }
    *(result + d) = '[=18=]';

    strcpy(p, result);

    free(result);
}

/* qsort C-string comparison function */
int compare_str (const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcmp(*ia, *ib);
}

为什么你有一个额外的换行符

如评论和答案中所述,当您使用 fgetsgetline。它会导致 len 中的字符数减少 1,然后 space 中的字符数减少 1。既然这本身不是犯罪,它只会导致您分配一个比需要的多的指针。但是,由于您对以下内容的定义,它会产生后果:

char* delim = "{ } . , ( ) ";

由于您没有指定 '\n' 作为分隔符,strtok 很乐意将其视为一个单独的词。这确实会导致您的排序出现问题,因为现在您的单词数组中出现了 空行 。因此,您可以在阅读 textStream 后删除换行符或将 '\n' 添加到 delim (或两者都正确)。

char* delim = "{ } . , ( ) \n";

不区分大小写排序

当想要在不受 LOCALE 影响的情况下排序时首先排序大写字母等。使用 strcasecmp 而不是 strcmp。所以在上面,只需将 qsort 比较更改为:

int compare_str (const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcasecmp(*ia, *ib);
}

strcasecmp 在 Windows

strcasecmp 是 linux 而非 windows 上可用的非标准函数。要包含相同的功能,请改用 stricmp。参见 (MSDN stricmp)。