【问题标题】:C program using char* crashing使用 char* 的 C 程序崩溃
【发布时间】:2018-07-28 15:09:50
【问题描述】:

目标是计算用户输入的 char* 中的所有元音。该程序还有其他功能,这是从 main 调用的。 我还包含了 stdio.h、stdbool.h 和 string.h

 char* countWord;
 int vowels;
 printf("Type the word to count vowels:");
 scanf("%s", &countWord);
 vowels = vowelCount(countWord);
 printf("%d", vowels);

以下是我使用的功能。我还尝试了 strlen(string) ,这也导致了崩溃。

int vowelCount(char* string){
    int vowels;
    int i;
    int size;
    printf("function entered");

    for (; *string; string++){
        if (string[i] == 'a'){
            vowels++;
        } else if(string[i] == 'e'){
            vowels++;
        } else if(string[i] == 'i'){
            vowels++;
        } else if(string[i] == 'o'){
            vowels++;
        } else if(string[i] == 'u'){
            vowels++;
        }

    }
    return vowels;
}

我做错了什么?我是 C 新手,但有其他语言的经验。 提前致谢。

【问题讨论】:

  • 指针指向哪里?它是一个有效的地址吗?请务必在使用前初始化/分配指针。
  • 我以为 char* countWord;初始化它
  • char *countWord(至少,对于自动存储持续时间的变量,在功能块中发生)定义了一个未初始化的指针。以任何方式访问其值或取消引用[访问该值然后尝试访问该地址处的内容](例如读取该地址处的内容,写入该地址)会产生未定义的行为。为未初始化的指针明确定义的唯一操作是为其赋值(例如,分配给实际地址)。

标签: c pointers char


【解决方案1】:

锻炼未定义的行为...

您没有为指向的指针分配任何空间,因此当您尝试使用它时,行为是未定义的。

只需为它腾出一些空间:

char buffer[1000];
char* countWord = buffer;

还有一个错误:

scanf("%s", &countWord);
            ^

您不应在此处使用 (&) 运算符的地址。扔掉它。您正在将字符串读入指针的目标,而不是指针本身。

另请注意,您在函数中执行了一些混合代码。您正在使用未初始化的变量i,但这似乎没有必要,因为您正在递增指针string。所以你想删除i并将if语句更改为

if (*string == 'a')

并且一定要初始化vowel

int vowel = 0;

【讨论】:

    【解决方案2】:

    从 scanf 手册页,格式说明符 %s:

    “匹配一系列非空白字符;下一个指针必须是指向 char 的指针,并且数组必须足够大以接受所有序列和终止 NUL 字符。”

    您的代码提供的与唯一 %s 说明符匹配的指针是声明为 char 指针的变量的 地址:&countWord 是指向 char 指针的类型指针。因此,scanf 将匹配的序列写入(或尝试写入)到大小适合指向 char 的指针的位置,不一定是序列长度 + 空终止符。因此,这可能会写入未分配的内存,这是未定义的行为(通常是段错误)。简单地删除地址操作符本身也不足以解决问题,因为简单地声明一个指向 char 的指针不会为您可能希望该指针在某个点指向的字符分配空间。

    使用 scanf 读取字符串时,您必须确保分配足够的空间来存储您将读取的序列,然后将 scanf 指针传递给该空间。这些可以静态分配:

    char countWord[512]; // Assumes input sequence will consist of no more than 511 characters, since space is needed for the terminating NUL character
    

    或动态:

    char* countWord = malloc(sizeof(char) * 512); // Same size as the above, so input still must be no more than 511 characters, but dynamically allocated so will need to be explicitly freed later to avoid leaking memory
    

    如果空间已分配且足够,则可以传递 countWord(以上面显示的任何一种方式定义,实际上是指向 char 的指针,不需要地址*) 如果您的 scanf 调用作为输入读取的序列在某些定义的输入限制下,您可以将 scanf 指针传递给为最大允许输入序列大小分配的足够空间,确保读取的序列不会超过分配的空间。

    然而,这取决于遵循上述限制的输入。最好让您的代码限制它可能读取的数量,因此即使您的输入源决定不按预期运行,也可以保证您不会访问未分配的内存。 scanf 通过在说明符中包含字段宽度来提供一种机制来执行此操作,例如:

    scanf("%511s", countWord); // Reads at most 511 bytes of input into the location pointed to by countWord, plus the NUL terminator.
    

    显然,您应该选择一个合适的数字,而不是输入的 511 个字符。程序的所有有效输入都应在其中。

    指出变量应该在读取之前初始化的另一个答案也是正确的,但是崩溃更可能是由于与未分配的内存交互而不是分配但仅仅是未初始化的内存(不是从后者读取不是未定义的)行为)。

    *从技术上讲,明确声明为数组的 char 数组和指向 char 的指针之间存在一些差异,但这些差异与这个问题并不特别相关。

    【讨论】:

      【解决方案3】:

      其他答案中已经提到了您对countWord 的内存分配不足。

      但是在计算元音时,您也遇到了使用未初始化变量的问题。 您使用 string 指针进行迭代,并在其上添加一些随机值 i

      int vowelCount(char* string){
        int i;  // <<=== not initialized, holding ramdon garbage value
      
        for (; *string; string++){
            if (string[i] == 'a'){  // << adding random index to pointer.
      ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多