0

我是新的 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 次 Chars b 出现 3 次

4

5 回答 5

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;
}
于 2013-09-09T08:44:44.050 回答
1

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

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

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

于 2013-09-09T09:03:11.230 回答
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(存在于 header<limits.h>中,您必须#include在程序开始时使用)。这是最大值。a 中的值unsigned char
该数组ch[]包含类型范围内每个可能值的组件unsigned char。意图是,对于某些字符c,元素ch[c]是在 中的c次数str
我已经使用unsigned char以确保写入时c数组的索引是非负整数值,因为数组不能有负索引。 第二个通过字符串。在步数中ch[]ch[c]
forstrj,取j字符串的第-个字符str
此字符是 type 的值char
由于无法确定char没有负值,因此我已(unsigned char)使用显式转换将其转换为。
该值保存在变量中c

的值在 中具有第j 个字符c的(版本) ,因此我们将对其进行计数。 如何? 好吧,我们访问计数器数组:使用 index ,并将其值增加 1: unsigned charstr

ch[]c

      ch[c]++;

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

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

第三个for'a''z',以及字母的值(c控制的变量for)和该字母的计数,即ch[c]

此外:要显示任何字符的计数,您需要重新转换为char,以这种方式:

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

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

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

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

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

   char letters[] = "abcdefghijklmnopqrstuvwxyz";

按照C的约定,“最后一个”元素是元素“z”之后的 \0 字符。

   Now, we can show the letter counting by changing the 3rd `for` in this way:  

 for (i = 0; letter[i] != '\0'; i++)
     printf("%c == %d\n", letter[i], ch[letter[i]]);

这相当于写:

 for (i = 0; letter[i] != '\0'; i++) {
     c = letter[i];
     printf("%c == %d\n", c, ch[c]);
 }
于 2013-09-09T08:29:20.610 回答
0

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

您的 void repeat 功能将是这样的,

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. 如果你想同时计算小写字母和大写字母。

像这样使用它

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.
于 2013-09-09T10:22:17.033 回答
-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;
于 2013-09-09T08:24:14.580 回答