【问题标题】:Returning NULL value from a function to a pointer in C将NULL值从函数返回到C中的指针
【发布时间】:2017-12-13 17:59:54
【问题描述】:

我有一个学校作业,我应该在其中创建三个函数。函数是 printFirstWord()、skipWords() 和 printWord()。

尽管写得并不完美,但我已经设法让 printFirstWord 函数正常工作,而其他两个函数大部分工作正常。

但是,在 skipWords() 中,如果您希望跳过的单词数量大于您输入的字符串中的单词数量,我应该返回一个指针值 NULL。这是我的代码:

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

//Call the functions
void printFirstWord(char inputString[]);
char* skipWords(char sentence[], int words);
void printWord(char sentence[], int wordNumber);

int main()
{
    printWord("I like to eat bunnies", 0); //Prints I
    printWord("I like to eat bunnies", 1); //Prints like
    printWord("I like to eat bunnies", 2); //etc
    printWord("I like to eat bunnies", 3);
    printWord("I like to eat bunnies", 4);
    printWord("I like to eat bunnies", 5); //This should return NULL
    printWord("I like to eat bunnies", 6); //This should return NULL

    return 0;
}

//Function that prints only the first word of a string
void printFirstWord(char inputString[])
{
    int i = 0;

    //Removes initial non-alpha characters, if any are present
    while (!isalpha(inputString[i]))
        i++;

    //Checks if the next input is alphabetical or is the character '-'
    while (inputString[i] != ' ')
    {
        printf("%c", inputString[i]);
        i++;
    }

}

char* skipWords(char sentence[], int words)
{
    int i = 0, wordCount = 0;

    for(i = 0; wordCount < words; i++)
    {
        if(sentence[i] == ' ')
        {
            wordCount++;
        }
    }

    //Can't get this to work, not sure how to return NULL in a function
    if (words >= wordCount)
        return NULL;
    else
        return &sentence[i];
}

void printWord(char sentence[], int wordNumber)
{
    char *sentencePointer;
    sentencePointer = skipWords(sentence, wordNumber);

    if (sentencePointer != NULL)
        printFirstWord(sentencePointer);
    else if (sentencePointer == NULL)
        printf("\nError. Couldn't print the word.\n");
}

最初我的问题是程序经常崩溃,但我添加了 printWord 函数的最后一部分并且它停止了崩溃。我期望这个输出:

Iliketoeatbunnies

Error. Couldn't print the word.

Error. Couldn't print the word.

这是我收到的输出:

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

指针是我的弱点,我觉得我错过了一些重要的东西,我一直在网上寻找,但我还没有找到任何适合我的解决方案,或者至少我觉得不适合我。

【问题讨论】:

  • 输入将是单个空格分隔的字符串?
  • 什么是单词?为什么要发布图片而不是好的 Unicode 文本?
  • @coderredoc 输入将是一个包含多个单词的句子,该函数应该指向用户选择的单词(int words)。基本上我所做的是,对于出现的每一个空格,程序都会知道另一个单词已经开始。这很简单,但它完成了现在需要做的事情。
  • 提示:当到达字符串末尾时,您的某些循环需要退出。
  • @lemonslayer 在复制格式化文本时,我有时会发现先将其粘贴到纯文本编辑器中,然后从那里复制/粘贴,最后添加目标所需的任何格式会更容易。

标签: c string algorithm split


【解决方案1】:

您的代码中几乎没有错误。更正将是

for(i = 0; sentence[i] && wordCount < words; i++)

另一个是

while (inputString[i] !=' ' && inputString[i]!='\0')

最后一个

if (words > wordCount)

第一个解释是 - 你不会检查字符串的末尾。否则你有未定义的行为。

当您到达字符串末尾但仍然没有空格时,可能会出现这种情况。为避免这种情况,您还需要考虑 \0 情况。

如果是words &gt; wordCount,那么只有你应该抛出错误。如果它们相等,则应打印该值。

【讨论】:

  • 啊,我正在考虑第一次更正,因为从技术上讲,它不会停止阅读最后一个单词并继续“在字符串之外”。关于最后的更正,当我写 >= 而不是 > 时到底发生了什么?我猜它总是相等的,这就是为什么它总是返回NULL?
  • @lemonslayer.: 是的
【解决方案2】:

skipWords 中的这个循环是问题所在。它将遍历字符串并超出,因为您没有检查字符串的结尾。

for(i = 0; wordCount < words; i++)
{
    if(sentence[i] == ' ')
    {
        wordCount++;
    }
}

由于退出循环的唯一方法是让它找到与words 一样多的空格,因此它将始终返回NULL

可以说wordCount 也应该从 1 开始,因为如果字符串中没有空格,您将始终至少有一个单词……除非字符串为空。

【讨论】:

  • 是的,我意识到循环表现得很奇怪,因为它在最后一个单词之后并没有停止。我同意 wordCount 应该从 1 开始,但分配非常明确,它应该从 0 开始。所以我想我必须以某种方式解决这个问题。
【解决方案3】:

我们初学者应该互相帮助。:)

你来了

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

char * skipWords( const char *s, size_t n )
{
    if ( n )
    {
        while ( isblank( ( unsigned char )*s ) ) ++s;

        do
        {
            while ( *s && !isblank( ( unsigned char )*s ) ) ++s;
            while ( isblank( ( unsigned char )*s ) ) ++s;
        } while ( *s && --n );
    }

    return ( char * ) ( *s ? s : NULL );
}

void printFirstWord( const char *s )
{
    while ( isblank( ( unsigned char )*s ) ) ++s;
    while ( *s && !isblank( ( unsigned char )*s ) ) putchar( *s++ );
}

void printWord( const char *s, size_t n )
{
    const char *word = skipWords( s, n );

    if ( word )
    {
        printFirstWord( word );
    }
    else
    {
        printf( "%s", "Error. Could not print the word." );
    }

    putchar( '\n' );
}

int main(void) 
{
    printWord("I like to eat bunnies", 0); //Prints I
    printWord("I like to eat bunnies", 1); //Prints like
    printWord("I like to eat bunnies", 2); //etc
    printWord("I like to eat bunnies", 3);
    printWord("I like to eat bunnies", 4);
    printWord("I like to eat bunnies", 5); //This should return NULL
    printWord("I like to eat bunnies", 6); 

    return 0;
}

程序输出是

I
like
to
eat
bunnies
Error. Could not print the word.
Error. Could not print the word.

至于你的代码,你通常不会像例子那样检查终止零

while (inputString[i] != ' ')
{
    printf("%c", inputString[i]);
    i++;
}

并忽略多个空格相互跟随的情况。

【讨论】:

    【解决方案4】:

    你在skipWords()的算法坏了,我改算法实现你的功能,把int改成size_t

    #include <stdio.h>
    #include <stddef.h>
    #include <ctype.h>
    
    int printFirstWord(char const *inputString);
    char const *skipWords(char const *sentence, size_t words);
    int printWord(char const *sentence, size_t wordNumber);
    
    int main(void) {
      printWord("I like to eat bunnies", 0); // Prints I
      printf("\n");
      printWord("I like to eat bunnies", 1); // Prints like
      printf("\n");
      printWord("I like to eat bunnies", 2); // etc
      printf("\n");
      printWord("I like to eat bunnies", 3);
      printf("\n");
      printWord("I like to eat bunnies", 4);
      printf("\n");
      printWord("I like to eat bunnies", 5); // This should return NULL
      printf("\n");
      printWord("I like to eat bunnies", 6); // This should return NULL
      printf("\n");
    }
    
    int printFirstWord(char const *inputString) {
      int ret = 0;
      while (isblank(*inputString)) {
        inputString++;
      }
      while (!isblank(*inputString) && *inputString) {
        int tmp = printf("%c", *inputString++);
        if (tmp < 0) {
          return -1;
        }
        ret += tmp;
      }
      return ret;
    }
    
    char const *skipWords(char const *inputString, size_t words) {
      while (isblank(*inputString)) {
        inputString++;
      }
      while (words > 0) {
        words--;
        while (!isblank(*inputString)) {
          if (!*inputString) {
            return NULL;
          }
          inputString++;
        }
        while (isblank(*inputString)) {
          inputString++;
        }
      }
      return *inputString ? inputString : NULL;
    }
    
    int printWord(char const *sentence, size_t wordNumber) {
      char const *sentencePointer = skipWords(sentence, wordNumber);
      if (sentencePointer != NULL) {
        return printFirstWord(sentencePointer);
      } else {
        fprintf(stderr, "Error. Couldn't print the word.\n");
        return -1;
      }
    }
    

    【讨论】:

    • 这对于我在课程中所处的位置来说太高级了,但是我会保存并查看它,以便我可以更好地编码!将 int 更改为 size_t 有什么作用?
    • @lemonslayer "这太高级了" => 这是故意的,所以你不能复制粘贴代码,除非你理解它;)。 "size_t" => stackoverflow.com/a/2550799/7076153, int 是一个很少保证的有符号整数,你写 printWord("I like to eat bunnies", -1); 有意义吗?可以说它可能的值取决于所需的行为,但根据您的练习,您的整数不应为负数,因此使用无符号类型是有意义的。加上size_t 能够处理任何索引大小,这使它非常有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 1970-01-01
    • 2014-08-16
    • 2010-09-07
    相关资源
    最近更新 更多