【问题标题】:character repetition in a file - case insensitive文件中的字符重复 - 不区分大小写
【发布时间】:2017-07-18 06:46:59
【问题描述】:

我编写了一个程序来计算文件中的字符数。我打算让程序不区分大小写。但我得到一个错误打印如下。

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

int main() {
    FILE *fp1;
    char c[100], f[20], k;
    int count = 0;

    printf("Enter the file name\n");
    scanf("%s", f);

    printf("Enter the character to be counted\n");
    scanf(" %c", &k);

    fp1 = fopen(f, "r");

    while (fscanf(fp1, "%c", c) != EOF) {
        if (strcmpi(c, k) == 0)
            count++;
    }

    fclose(fp1);

    printf("File '%s' has %d instances of letter %c", f, count, k);
    return 0;
}

在这个程序中我收到一个错误提示

warning: passing argument 2 of 'strcmpi' makes pointer from integer without a cast [-Wint-conversion]

我能做些什么来纠正它?

【问题讨论】:

  • 提示:ck 的数据类型(或者只是“类型”)不一样。
  • 如果您使用fgetc一次读取一个字符,这个程序可以更容易编写。
  • 您可以使用tolowertoupper 将一个字符变为小写/大写。
  • 我不知道为什么你甚至需要 strcmpi 函数,如果你只是比较字符只是直接比较字符这绝对是矫枉过正 一次获取一个字符通常比较它,即c==k
  • strcmpi 绝对是non-standard

标签: c string file pointers


【解决方案1】:

您的代码存在多个问题:

  • char f[20]; 对于许多文件名来说可能太短了。
  • 您应该通过提供要存储到数组中的最大字符数来防止scanf() 中的缓冲区溢出:scanf("%19s", f);
  • 您应该测试scanf() 返回值以避免在转换失败时出现未定义的行为。
  • 您应该测试fopen 是否成功。
  • 不应将char 值传递给非标准函数strcmpi,而应通过标准函数tolower&lt;ctype.h&gt; 将字符转换为小写:

    if (tolower((unsigned char)k) == tolower((unsigned char)c[0]))
        count++;`
    

    tolowerchar 参数被转换为 (unsigned char) 以避免传递行为未定义的潜在负值。

这是一个更正的版本:

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

int main(void) {
    FILE *fp;
    char f[1024], k;
    int lower_k, c;
    int count = 0;

    printf("Enter the file name: ");
    if (scanf("%1023s", f) != 1)
        return 1;

    printf("Enter the character to be counted: ");
    if (scanf(" %c", &k)) != 1)
        return 1;

    fp = fopen(f, "r");
    if (fp == NULL) {
        printf("cannot open file '%s'\n", f);
        return 1;
    }

    lower_k = tolower((unsigned char)k);
    while ((c = getc(fp)) != EOF) {
        if (tolower(c) == lower_k)
            count++;
    }

    fclose(fp);

    printf("File '%s' has %d instances of letter %c\n", f, count, k);
    return 0;
}

注意事项:

  • 文件名f不能包含空格。
  • 此程序无法计算空白字符,因为scanf(" %c", &amp;k) 会跳过它们,直到您键入非空白字符。

考虑使用fgets() 来读取输入并修复这些缺点。

编辑如果你想要或必须使用函数strcmpi,你应该将字符读入第二个字节为空字节的2字节数组中,以使这些数组正确的字符串传递给@ 987654339@,但是这个解决方案效率很低

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

int main(void) {
    FILE *fp1;
    char f[100], c[2] = "", k[2] = "";
    int count = 0;

    printf("Enter the file name\n");
    if (scanf("%99s", f) != 1) return 1;

    printf("Enter the character to be counted\n");
    if (scanf(" %c", k) != 1) return 1;

    fp1 = fopen(f, "r");
    if (fp1 != NULL) {
        while (fscanf(fp1, "%c", c) == 1) {
            if (strcmpi(c, k) == 0)
                count++;
        }
        fclose(fp1);

        printf("File '%s' has %d instances of letter %s\n", f, count, k);
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    要不区分大小写地比较字符,只需使用tolower()toupper() 将它们都转换为相同的大小写。

    #include<stdio.h>
    #include<ctype.h>
    
    int main()
    {
        FILE *fp1;
        char f[20], k;
        int c;
        int count = 0;
    
        printf("Enter the file name\n");
        scanf("%s",f);
    
        printf("Enter the character to be counted\n");
        scanf(" %c",&k);
        int k_int = tolower((unsigned char)k);        
    
        fp1 = fopen(f,"r");
    
        while((c = fgetc(fp1)) != EOF)
        {
            if(tolower(c) == k_int) {
                count++;
            }
        }
    
        fclose(fp1);
    
        printf("File '%s' has %d instances of letter %c\n", f, count, k);
        return 0;
    }
    

    【讨论】:

    • 您应该用scanf("%19s", f); 保护f,转换k 以将正值传递给tolower()k = tolower((unsigned char)k);,并可能在最后一个printf 中输出一个换行符。
    • tolower 的签名是int tolower(int),所以它会自动转换它的参数。
    • tolower() 只为unsigned char 类型的值和EOF 值定义。如果你传递一个负的char 值,你有未定义的行为。
    • 类型应该是int,值必须在unsigned char的范围内。但scanf() 不应返回该范围之外的任何内容。
    • scanf() 将字节存储到k 中,这是一个char 变量。如果类型 char 已签名并包含负值(例如 é,其 ISO-8859-1 编码为 0xe9,因此值 -23 具有大多数默认编译器设置),将 k 传递给 tolower 具有未定义的行为。 k 必须转换为 (unsigned char)k 以防止这种情况。此外,您应该将来自tolower((unsigned char)k) 的返回值存储到int 中以避免if (tolower(c) == k) 中出现不同的问题,因为(unsigned char)'é' != 'é')'é' 为负数的系统上。
    【解决方案3】:

    strcmpi 需要两个指向字符串的指针。但是您按值传递 k 。那是char

    char c[100], f[20], k;
    // ...
        if(strcmpi(c,k)==0)  count++;
    //...
    // fix:
        if(strcmpi(c,&k)==0)  count++;
    

    您或许应该考虑使用符合 POSIX 的 _stricmp 而不是 strcmpi。

    【讨论】:

      【解决方案4】:

      您甚至不需要使用 strcmpi() 来表示您可以直接比较两个字符的字符:

      if(tolower(c) == tolower(k))  
        count++; 
      

      【讨论】:

      • 这是区分大小写的。
      • 你甚至不需要使用strcmpi():这有点误导,实际上使用strcmpi()是完全错误的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-08
      • 2014-04-11
      • 2012-02-29
      • 2014-06-20
      • 1970-01-01
      • 2013-07-22
      相关资源
      最近更新 更多