【问题标题】:strcmp(string,string) for palindrome checkerstrcmp(string,string) 用于回文检查器
【发布时间】:2020-08-24 07:56:54
【问题描述】:

作为 uni 入门级软件开发的编程任务,我们的任务是制作一个程序:

  • 让用户输入一个字符串
  • 输出字符串的长度
  • 输出字符串是否是回文(在两个方向上读取相同,即赛车向后是赛车)
  • 输出反转的字符串

  • 我们正在使用 C。我对 C 的经验很少,但 C++/C# 是熟悉的领域。 C 没有常​​规字符串。
    在 C 中,如果要对字符串进行计算,请使用 char 数组。
    我已经制作了一个简单、有效的程序版本,它只使用一个 for 循环来反转字符串,但我想通过制作一些函数来处理程序的不同部分来挑战自己。

    问题也就是说,该函数旨在返回一个布尔值,指示字符串是否为回文,无论输入如何,都会返回相同的值。然而,由另一个函数处理的字符串反转可以正常工作,如第三个输出值所示。这让我相信我对strcmp 的理解存在问题,或者我不完全理解我的代码如何操作字符串。

    测试输入和输出示例。
    输入:
    bob
    输出:
    The word contains 3 letters The word is not a palindrome The word reversed is 'bob'
    这里的代码应该输出bob是回文,表明比较没有正确运行。

    输入:
    fish
    输出:
    The word contains 4 letters The word is not a palindrome The word reversed is 'hsif'

    我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    
    //Reverses a string, Takes the string, a pointer to allocated memory and the length of the substring to be reversed
    void stringReverse(const char s[], char *mem, int n) {
        char b[n + 1];
        b[n + 1] = 0;
        for (int i = 0; i < n; i++) {
            b[i] = s[n - (i + 1)];
        }
        strncpy(mem, b, n);
    }
    
    //Checks if 's' is a palindrome
    bool isPal(char s[], char *c) {
        stringReverse(s, c, (int)strlen(s) + 1);
        //printf("%s", s); //used for debugging
        return !strcmp(c, s);
    }
    
    int main() {
        char word[100];
        gets(word);
    
        //This loop used alone works. Calling strcmp(word,rev) in place of isPal(word,c) as well as replacing c with rev in line 38.
        //    char rev[(int)strlen(word)+1];
        //    for(int i = 0; i<=(int)strlen(word);i++){
        //        if(i==(int)strlen(word)){rev[i]=0;continue;}
        //        rev[i]=word[(int)strlen(word)-(i+1)];
        //    }
    
        char *c = malloc(strlen(word) + 1);
        printf("The word contains %d letters\n", (int)strlen(word));
        printf("The word is%s a palindrome\n", isPal(word, c) ? "" : " not");
        stringReverse(word, c, (int)strlen(word));
        printf("The word reversed is '%s'\n", c);
        free(c);
        return 0;
    }
    

    【问题讨论】:

    • 首先你应该编辑你的输出示例。 bob 是回文。
    • stringReverse(s,c, (int)strlen(s)+1); -> stringReverse(s,c, (int)strlen(s));
    • @kaylum 在这种情况下返回的字符串不会以空值结尾,从而导致进一步的问题。这是一个不同的问题,我只是在我的教授的帮助下没有解决。
    • gets 已被标记为过时 25-30 年,并在 9 年前完全从 C 语言中删除。你为什么还在用它?您的学习来源必须完全过时。
    • char b[n+1]; b[n+1]=0; 立即错误,因为它创建了一个包含 n+1 个元素的数组并设置了第 (n+2) 个元素。 (记住,索引是从零开始的。)可能还有其他问题。

    标签: arrays c string


    【解决方案1】:

    您的代码中存在多个问题:

    • b[n + 1] = 0; 在数组末尾存储 0

    • strncpy(mem, b, n); 不会终止目标数组。不要使用strncpy,它的语义令人困惑且容易出错。由于malloc()返回的块是未初始化的,所以偏移量b[n]处的字节不一定是0,因此导致strcmp()返回非0。

    • stringReverse(s, c, (int)strlen(s) + 1); 使用了错误的字节数值,你甚至不应该传递字节数,只需在stringReverse 中使用strlen(s)。

    • gets() 已弃用且不安全。它已从最新版本的 C 标准中删除。不要使用gets(),而是使用fgets() 或scanf()。

    注意,反转后的字符串可以直接存储到目标数组中。

    这是修改后的版本:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    
    // Reverse a string:
    //   takes a pointer to a source string and a pointer to a destination array.
    //   the destination array must be long enough.
    //   the source and destination array must not overlap.
    //   returns a pointer to the destination array (like strcpy)
    char *stringReverse(char *dest, const char *src) {
        size_t len = strlen(src);
        for (size_t i = 0; i < len; i++) {
            dest[i] = src[len - (i + 1)];
        }
        dest[len] = '\0';
        return dest;
    }
    
    //Checks if 's' is a palindrome
    bool isPal(const char *s) {
        char tmp[strlen(s) + 1];
        stringReverse(tmp, s);
        //printf("%s", s); //used for debugging
        return !strcmp(tmp, s);
    }
    
    int main() {
        char word[100];
    
        if (scanf("%99[^\n]", word) != 1)
            return 1;
    
        int len = strlen(word);
        printf("The word contains %d letters\n", len);
    
        char *p = malloc(len + 1);
        if (p != NULL) {
            printf("The word is%s a palindrome\n", isPal(word) ? "" : " not");
            printf("The word reversed is '%s'\n", stringReverse(p, word));
            free(p);
        }
        return 0;
    }
    

    输入:bob

    输出:

    The word contains 3 letters
    The word is a palindrome
    The word reversed is 'bob'
    

    【讨论】:

      【解决方案2】:

      由于您的输出正确打印了反转的字符串,您可以假设函数stringReverse() 可以正常工作。在您的代码中,您有两个函数调用:

      1. 在main()中打印的结果是正确的:

        stringReverse(word,c,(int)strlen(word));
        
      2. 但是在isPal() 你有问题:

        stringReverse(s,c, (int)strlen(s)+1);
        

      从后面的调用中删除+1,你应该没问题:

         stringReverse(s,c, (int)strlen(s));
      

      正如其他人所提到的,可能有更好的方法来解决这个问题。

      【讨论】:

      • 就像问题中提到的那样,我已经有了一个简单的工作版本,我故意将其复杂化以挑战自己和学习。我会检查你的建议并检查它是否有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-06
      • 2017-02-18
      • 2015-06-09
      • 2015-05-27
      • 2010-12-28
      相关资源
      最近更新 更多