【问题标题】:How do would I alphabetize the strings in my character array?如何按字母顺序排列我的字符数组中的字符串?
【发布时间】:2015-05-21 22:59:42
【问题描述】:

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

【问题讨论】:

  • 你可以使用 qsort() 吗?这可能是无需自己编写即可进行排序的最简单方法。

标签: c arrays char words


【解决方案1】:

当你真正开始工作时,我想你会大吃一惊。 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) 中的指针/int 不匹配应该是if (*pointer == ch),您的代码不会启用。。 p>

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

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

char textStream[100] = {0};     //up to 98 characters and '\n\ and '\0'
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

使用/输出示例

$ ./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 函数中有 很多 不相关的代码。我没有花时间把它去掉,因为这并没有阻止你说的话。带有上述修改的代码编译时不会发出警告。所以我会留给你去通过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);
}

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

正如 cmets 和答案中所述,当您使用 fgetsgetline 阅读时,始终从字符串中去除尾随的 '\n' 是一个好主意。这将导致您在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);
}

Windows 上的 strcasecmp

strcasecmp 是一个非标准函数,在 linux 上可用,在 windows 中不可用。要包含相同的功能,请改用stricmp。请参阅 (MSDN stricmp)。

【讨论】:

  • 我按照你的方式实现了代码,我没有收到任何错误或警告,但这些词实际上并没有得到排序。
  • 嗯。您是否已发布所有代码?我会看一下,但这可能是其中一个微妙但重要的区别。
  • 好的,我去看看,同时,看看我发布的完整示例
  • @Karlioh - 我说你应该从textStream 中删除尾随'\n' 是有原因的。查看main:p 中的差异(这将导致len 中的字符计数减少1,然后space 计数减少1)。 (您可以将'\n' 添加到delim 作为另一种修复方式)
  • 代码几乎是完美的,除了数组的第一个索引从不排序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-07
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多