在C中用字符串计算字符数的函数

时间:2013-09-09 08:16:11

标签: c string

我是新来的C.我想得到帮助来完成我的职能。

任务是:

编写一个接受字符串maximum length of 256 characters containing characters from 'a' to 'z'的函数。

打印每个字符出现次数的功能。

例如:输入abba输出将为:

a = 2 b = 2 c = 0 d = 0 .... z = 0

在任何功能期间不要使用if。

我想请你帮忙完成这个程序。

这是我的代码

#include "stdlib.h"
#include "conio.h"
#include "stdio.h"
#include "string.h"
#define size 256



void repeat(char *str);
void main()
{
    char str[size];
    printf("Please enter a string:\n");
    flushall;
    gets(str);
    repeat(str);
    system("pause");
    return ;
}
void repeat(char *str)
{

    char temp=strlen(str);
    int i, count=0;
    do
    {
    for (i=0; i<temp ; i++)
        {
            count += (*str == str[temp-i]);
        }
    printf("Char %c appears %d times\n ",*str,count);
    count=0;
    }
    while(*(str++));
}



    Please enter a string:
abbba
Char a appears 1 times
 Char b appears 2 times
 Char b appears 1 times
 Char b appears 0 times
 Char a appears 0 times
 Char   appears 0 times
 Press any key to continue . . .

这是输出! 我想在我做的同一栋楼里做。 应该是这样的 Char a出现2次 字符b出现3次

5 个答案:

答案 0 :(得分:3)

您对不使用if做出了规定。这满足了这个限制。

#include <stdio.h>

int main(void) {
    int i, c;
    int counts[256] = { 0 };
    const char lower[] = "abcdefghijklmnopqrstuvwxyz";
    while ((c = getchar()) != EOF) {
        counts[c] += 1;
    }
    for (i = 0; lower[i]; ++i) {
        c = lower[i];
        printf("Char %c appears %d times.\n", c, counts[c]);
    }
    return 0;
}

您尝试的问题是您没有跟踪任何状态以记住您已经打印过哪些字符的信息。它也未能将所考虑的字符作为计数的一部分。它还会对字符串进行多次传递以收集有关每个字符的计数信息,但这不会影响正确性,只会影响性能。如果你能以某种方式记住你已经打印出哪些字符的信息,那么当字符串后面出现相同的字符时你不再这样做,你的方法应该打印掉出现的字符的计数。之后,您需要打印出根本没有出现的字符的零计数。如果输出需要按字母顺序排列,那么你需要确保你也要照顾它。

正确跟踪信息并允许按字母顺序打印输出的一种方法是维护数组中每个字符的计数。在对字符串进行传递并递增与每个找到的字符关联的计数后,您可以迭代计数数组,并打印出计数。


以下程序适用于zubergu:

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

int main (void) {
    int i, c;
    int counts[26] = { 0 };
    const char lower[] = "abcdefghijklmnopqrstuvwxyz";
    while ((c = getchar()) != EOF) {
        switch (c) {
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
        case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
        case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
        case 'v': case 'w': case 'x': case 'y': case 'z':
            counts[strchr(lower, c) - lower] += 1;
            break;
        default:
            break;
        }
    }
    for (i = 0; lower[i]; ++i) {
        printf("Char %c appears %d times.\n", lower[i], counts[i]);
    }
    return 0;
}

答案 1 :(得分:1)

它可能是最丑陋的解决方案之一,也是最简单的解决方案:

while(*str!='\0')
{
  switch(tolower(*str))
  {
    case 'a': a_count++;break;
    case 'b': b_count++;break;
    .
    .
    .
  }
  str++;
}

它检查str是否指向有效字母,然后将其降低,因此它不区分大小写('A'将与'a'字符相同)。没有使用'if',并且将使用以'\ 0'字符结尾的每个长度字符数组。

答案 2 :(得分:0)

编辑我已编辑该程序以符合@SagiBinder的要求。

(在我的旧版本中,我使用if句子来检查角色是否在集合'a'...'z')中。

temp的类型必须“更大”,即与char不同的内容。
请改为int

算法就是这个(程序的一些细节不再重复):

int temp = strlen(str);

int i, j;

unsigned char c; 

int ch[UCHAR_MAX]; // The macro CHAR_MAX needs the header <limits.h>
for (i = 1; i <= UCHAR_MAX; i++)
    ch[i] = 0;

for (j=0; j<temp ; j++) {
      c = (unsigned char)(str[j]);
      ch[c]++;
}

for (c = 'a'; c <= 'z'; c++)
    printf("%c == %d\n", c, ch[c]);

变量temp保存字符串str的长度 宏UCHAR_MAX(存在于标题<limits.h>中,您必须在程序开头#include。这是最大的。 unsigned char中的值 数组ch[]包含unsigned char类型范围内每个可能值的组件。意图是,对于某些字符c,元素ch[c]cstr中的次数。
我使用unsigned char来确保写c时数组ch[]的索引ch[c]是非负整数值,因为数组不能有负索引。
第二个for遍历字符串str。在步骤编号j中,采用字符串j的{​​{1}}个字符。
此字符是str类型的值 由于无法确定char没有负值,因此我已使用显式转换将其转换为char。 该值保存在变量(unsigned char)中。

c的值包含c中第j个字符的{unsigned char版本, 所以我们要算一算。
怎么样?
好吧,我们访问具有索引str的计数器数组ch[],并将其值增加为1:

c

ch[c]++; 完成后,我们在数组for中有我们想要的信息。

最后,我们检查从ch[]'a'的字符 (为此,我们假设我们系统中的字符编码遵循字母具有连续值)的约定。

第3个'z'for转到'a',以及字母的值(控制'z'的变量c)和计数这封信,即for

此外:要显示任何角色的数量,您需要以这种方式重新投射到ch[c]

char

但是字母'a'到'z'不是必需的,因为它们属于基本执行字符集,这意味着它们的值是非负的并且等于它们的{{ 1}}对应物。所以,在这种情况下,写下来就足够了:

    printf("%c: %d\n", (char)c, ch[c]);

编辑2:我会在 @jxh 的答案中使用这个想法来改进我的代码。

由于不能保证字母'a'到'z'的编码是连续的顺序,我们可以使用一个包含字母的字符串:

unsigned char

“last”元素是通过 C 约定,在元素“z”之后保存的\ 0字符。

    printf("%c: %d\n", c, ch[c]);

这相当于写:

   char letters[] = "abcdefghijklmnopqrstuvwxyz";

答案 3 :(得分:0)

优化解决方案。复杂度O(N),N - 输入字符串长度。

你的虚假重复函数将是这样的,

void repeat(char *str)
{

    int temp=strlen(str);// use int here
    int i, count=0;
int charCount[26] = {0};


#if 0
//your logic, traverses the string (n*n) time, n - input string length.
    do
    {
        for (i=0; i<temp ; i++)
        {
            count += (*str == str[temp-i]);
        }
        printf("Char %c appears %d times\n ",*str,count);
        count=0;
    }
    while(*(str++));
#endif

#if 1
// This logic traverses string once only. n time, n - input string length.
for (i=0; i<temp ; i++)
    {
        charCount[str[i]%'a']++;
    }

for (i=0; i<26 ; i++)
    {
        printf("%c appears :  %d times \n", 'a'+i, charCount[i]);
    }
#endif
}

[编辑] 在这里

charCount[str[i]%'a']++; // 'a' is used a its ASCII Value.

您可以将其用作

charCount[str[i]%97]++;
  1. 如果你想计算小写字母和大写字母。
  2. 像这样使用

    if(str[i] >= 'a' && str[i] <= 'z'){
            iMap = str[i]%97; // 97 is ASCII Value of 'a'
            charCount[iMap]++;
        }else if(str[i] >= 'A' && str[i] <= 'Z'){
            iMap = str[i]%65; // 65 is ASCII Value of 'A'
            charCount[iMap]++;
        }
    //iMpa is a integer (int iMap;), used for better undersanding.
    

答案 4 :(得分:-1)

 i = 0;
  while (s[i] !=0)
   if (( s[i] >= 'a' && s[i] <= 'z') || (s[i] <= 'A' && s[i] >= 'Z'))
   {
     letters++;
     i++;
   }
   else
     if (( s[i] >= '!' && s[i] <= ')'))
     {
       other++;
     }
   else
     if (( s[i] >= '0' && s[i] <= '9'))
     {
       numbers++;
     }
      total = letters + numbers + other;