C:函数声明

C : Function Declaration

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

 int count_letters(string text[]);
 int main(void)
 {
    string text= get_string("Please enter text: ");
    printf("%i Letter(s)  \n",countl);
 }
 int count_letters(string text[])
 {
    int countl= 0;
    for (int i = 0, n = strlen(text); i < n; i++)
    {
      if (isalpha(text[i]) != 0)
      {
        countl++;
      }
  }
  return countl;
  }

大家好,我查阅了我的教科书和各种教育资源“如何在C中声明一个函数”,我仍然无法实现。在此代码中,我希望函数 count_letters 到 return 值“countl”,然后我可以将其打印在屏幕上。请帮助我了解如何正确声明此功能。

查看 cs50.h header 了解 string 是如何定义的:

typedef char *string;

所以

int count_letters(string text[]);

定义了一个char.

的指针数组

当索引 text[i] 时,编译器 returns 一个 string 而像 isalpha 这样的函数期望一个 char。输入中的一维过多。

你只需要一个字符指针(常量也更好)。没有 cs50 包含,因为 count_letters 没有修改 text 数据,我会写:

int count_letters(const char *text);

所以如果你真的想使用 cs50 类型,请选择:

int count_letters(const string text);

因为 string 是类型 char * 的别名,所以这个函数声明

int count_letters(string text[]);

相当于声明

int count_letters( char * text[] );

这又等同于

int count_letters( char ** text );

所以在函数中,例如这些表达式

strlen(text) 

isalpha(text[i])

是不正确的,因为在第一个表达式中使用的参数具有类型 char ** 而不是类型 char * 并且在第二个表达式中参数具有类型 char * 而不是 char.

而且 strlen 的调用是多余的。

函数应按以下方式声明和定义

size_t count_letters( string text );

size_t count_letters( string text )
{
    size_t countl = 0;

    for ( ; *text; ++text )
    {
        if ( isalpha(( unsigned char )*text ) ) ++countl;
    }

    return countl;
}

注意函数声明如下方式更正确

size_t count_letters( const char *text );

因为传递的字符串在函数中没有改变。写 const string text 没有意义,与 const char *

不一样

而且你忘了调用main中的函数。你必须写

printf("%zu Letter(s)  \n", count_letters(text ) );

您的程序有两个主要问题。

1.

count_letters 的参数 text 类型错误。 stringchar *cs50.h 别名。 text 需要是 stringchar *char [] 类型之一,在这种情况下作为函数参数等同于 char *.

使用其中之一

int count_letters (string text)

int count_letters (char* text)

int count_letters (char text[])

但不是

int count_letters (string text[])

With string text[] text 将是 char ** 类型,这是错误的,因为您不想修改 count_letters.[=52 中的指针本身=]

可选地,您也可以将指针 and/or 设为指向对象 const 以确保不会被误用或覆盖。

2.

您永远不会在 main 中调用函数 count_letters。您需要调用它以获取其 returned 值。

 int main(void)
 {
    string text = get_string("Please enter text: ");
    printf("%i Letter(s)  \n", count_letters(text));
 }

旁注:

  • 您应该将 isalpha() 的参数转换为 unsigned char 以确保在未传递适当的字符时不会出现 undefined behavior

  • n = strlen(text); i < n;count_letters 中的 for 循环中可以只用条件 text[i] != '[=39=]' 或更简单的 text[i].

  • 由于您不打算提供负 return 值,因此您可以使用 return 类型的 unsigned intsize_t check_letters。您也需要将 mainprintf() 调用中的格式说明符更改为 %u for unsigned int%zu for size_t.


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

 unsigned int count_letters (const string text);

 int main (void)
 {
     const string text = get_string("Please enter text: ");
     putchar('\n');         
     printf("%u Letter(s)  \n", count_letters(text));
 }

 unsigned int count_letters (const string text)
 {
     unsigned int countl = 0;
     for (unsigned int i = 0; text[i] ; i++)
     {
         if (isalpha((unsigned char)text[i]))
         {
             countl++;
         } 
     }

     return countl;
 }

执行:

./a.out
Please enter text: hello
5 Letter(s)  

Online Test

参数的类型需要与您传递的表达式的类型相匹配 - 在这种情况下,您将传递类型 string 的表达式,因此原型需要是

int count_letters(string text)

要获得该计数,您必须调用 来自main 的函数。您可以在 printf 内调用:

printf("%i Letter(s)  \n", count_letters(text));

或者您可以创建另一个变量来存储该结果:

string text = get_string( ... );
int len = count_letters( text );
printf( "%i Letter(s)  \n", len );

变量 countlcount_letters 函数的局部变量,无法从 main 访问。

<无端咆哮>

CS50 string typedef 名称是一个 谎言 因为它别名 不是字符串 ,并且在看够了之后参加CS50课程的人的问题我认为这实际上是学习C的障碍;它 完全 歪曲了字符串的表示和处理方式,如果您在本课程之外进行任何 C 编程,您将完全没有准备好如何处理字符串(以及 I/O 一般而言)实际工作。

放松点,这需要一段时间。

在 C 语言中,字符串 是一个包含零值 终止符 的字符序列。字符串 "hello" 表示为序列 {'h', 'e', 'l', 'l', 'o', 0}.

字符串(包括像 "hello" 这样的字符串文字)存储在字符类型的数组中:

char text[] = "hello"; // array size is determined by the length of the initializer

char text[SOME_SIZE]; // where SOME_SIZE is large enough to store what we need
strcpy( text, "hello" );

由于字符串存储在数组中,您不能使用 = 运算符来分配它们(如上所示在初始化器之外,但这仅对 声明有效).您要么需要使用像 strcpy(对于包含字符串的数组)或 memcpy(对于包含任何其他内容的数组)这样的库函数,要么您需要单独分配每个元素:

text[0] = 'h';
text[1] = 'e';
...
text[5] = 0;

现在,在大多数情况下,类型为“T 的数组”(包括像 ”hello" 这样的字符串文字)的 表达式 将被转换为 (" decay”)到类型为“指向T”的表达式,表达式的值将是第一个元素的地址。所以,如果我们调用一个像

这样的函数
count_letters( text );

写的完全一样

count_letters( &text[0] );

count_letters实际接收到的是指针类型char *,我们将原型声明为

int count_letters( char *str ) {...}

当你写类似

的东西时
char *str = "hello";

您将字符串第一个字符的 地址 分配给 str,而不是字符串内容本身。

stringcs50.h 中定义的类型 char * 的 typedef 名称或别名。它不是 C 语言或标准 C 库的一部分。问题是 char * 不是字符串 。它可能指向字符串的第一个字符。它可能指向 不是 字符串的序列的第一个字符。它可能指向一个不属于更大序列的单个字符。当我们处理字符串时,我们经常处理 char * 类型的表达式,但是 char * 类型的表达式本身并不是字符串。

get_string 函数(同样是 cs50 库的一部分,而不是标准的 C 库函数)在幕后执行了很多魔法 动态地 分配一个数组来存储字符串和 returns 一个 指针 到第一个元素(这是你实际分配的)。它很漂亮,很方便,但同样,它 完全 歪曲了 C 实际做事的方式。