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

时间:2015-05-21 22:59:43

标签: c arrays char words

我编写了一个程序,用于计算用户输入的字符串中字母和单词的出现次数。我已经成功地完成了大部分工作,但是,我还必须将我存储在指针数组中的单词按字母顺序排列。我看到一个函数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 '\0'

    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] != '\0') // loop until prt[i] is '\0'
    {
        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) = '\0';

        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 '\0'
    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] != '\0') // loop until prt[i] is '\0'
    {
        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);
}

1 个答案:

答案 0 :(得分:2)

当你确实让它发挥作用时,我认为你会感到惊讶。 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);
}

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

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

(其中count是您的space + 1等效物)。现在,在我们查看答案之前,您需要在编译时启用警告(由于if (pointer == ch)中的指针/ int不匹配,您的代码不应该是if (*pointer == ch) findWords -Wall -Wextra 1}}。

但除此之外,在启用警告的情况下进行编译会在char textStream[100] = {0}; //up to 98 characters and '\n\ and '\0' size_t len = 0; 中指出一系列问题。要启用警告,请将fgets添加到编译字符串中。

现在让我们看一下代码的变化。 始终初始化所有变量

getline

接下来,在使用newlineif (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]);
    }
}

现在,更改为gcc -Wall -Wextra -o yourprog yourfile.c

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

编译时,应该有 NO 警告:

findWords

示例使用/输出

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 '\0' 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] != '\0') // loop until prt[i] is '\0' { 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) = '\0'; 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); } 函数中存在很多不相关的代码。我没有花时间去除它,因为这并不能阻止你的话。具有上述修改的代码在没有警告的情况下编译。因此,我会留给你去'\n'然后去掉那些不需要的东西。

完整示例

fgets

为什么你有额外的换行

正如评论和答案中所提到的,当您使用getline或{阅读时,始终最好从字符串中删除尾随的len {1}}。这将导致1中的字符数被space关闭,然后1计数将被char* delim = "{ } . , ( ) "; 关闭。既然这本身并不构成犯罪,那么它只会让你分配一个超过需要的指针。但是,由于您的定义,它会产生后果:

'\n'

由于您未指定strtok作为分隔符,因此textStream乐意将其视为单独的单词。这会导致您的排序出现问题,因为现在您的单词数组中出现了空行。因此,您可以在阅读'\n'或将delim添加到char* delim = "{ } . , ( ) \n"; (或两者都适用)后删除换行符。

strcasecmp

不区分大小写排序

如果想要在没有LOCALE排序大写字母效果的情况下进行排序等,请使用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

stricmp是Linux上可用的非标准函数,而不是在windows中。要包含相同的功能,请改用{{1}}。见(MSDN stricmp)。