【问题标题】:What is wrong with my squeeze() function?我的squeeze() 函数有什么问题?
【发布时间】:2021-04-11 14:17:27
【问题描述】:

现在,我正在阅读“C 编程语言”一书,这是一次令人羞愧的经历。现在我正在做本书中的练习 2-3,我不知道我的挤压()函数哪里出了问题。该函数的目的是删除字符串 1 中在字符串 2 中找到的所有字符。现在我的函数所做的就是删除 string1 的第一个字符,如果它在 string2 中找到,然后在此之后出现奇怪的行为。我查看了答案簿和给出的答案让我很困惑。很难理解正在做的事情,所以我不想遵循答案簿中的逻辑,而是想知道我自己的代码哪里出错了……下面是代码:

/* Write an alternate version of squeeze(s1, s2) that deletes each char in s1 that matches
*  any char in string s2 */

/* Here's a reference for squeeze(s1, s2):
*  squeeze: delete all c from s
*
*  void squeeze(char s[], int c)
*  {
*   int i, j;
*
*   for(i = j = 0; s[i] != '\0'; i++)
*       if(s[i] != c)
*           s[j++] = s[i];
*   s[j] = '\0';
*  }
*******************************************/

#include <stdio.h>
#include <string.h>
#define MAX_INPUT 100

void squeeze(char string1[], char string2[]);

int main()
{
    int c, i = 0, j = 0;
    char s1[MAX_INPUT + 2], s2[MAX_INPUT + 2];
    printf("\nPlease enter string1\n");
    while((c = getchar()) != '\n')
    {
        s1[i] = c;
        i++;
    }
    s1[i] = '\0';
    /* test to see if above worked */
    printf("\ns1 = %s\n", s1);

        printf("\nPlease enter string2\n");
        while((c = getchar()) != '\n')
        {
                s2[j] = c;
                j++;
        }
    s2[j] = '\0';
        /* test to see if above worked */
        printf("\ns2 = %s\n", s2);

    printf("\nWe will now apply the squeeze function to remove any chars");
    printf(" found in string2 from string1\n");
    squeeze(s1, s2);
    printf("Squeeze(s1, s2) = %s\n", s1);
}

void squeeze(char s1[], char s2[])
{
    int i = 0, j = 1;   /* for counters */
    char temp;  /* for char comparison */
    temp = s2[0];

    while(s2[i] != '\0')
    {
        if(s1[i] == temp)
        {
            s1[i] = s1[i+1];
            j++;
        }
        else
        {
            j++;
        }
        temp = s2[j];
        i++;
    }
    s1[i+1] = '\0';

}

我的输出如下:

Please enter string1
hello

s1 = hello

Please enter string2
help

s2 = help

We will now apply the squeeze function to remove any chars found in string2 from string1
Squeeze(s1, s2) = eello

谁能发现我的逻辑有什么问题?从答案簿中,我猜我需要第三个计数器 k,在某个地方,但我无法通过我对函数进行编程的方式看到它的原因。我知道我错过了一些东西!非常感谢大家:)

回答(谢谢弗拉德!):

void squeeze(char s1[], char s2[])
{
        int i = 0, j = 0;

        do
        {
                int k = 0;
                while(s2[k] != '\0' && s2[k] != s1[i])
                ++k;

                if (s2[k] == '\0')
                {
                        if ( j != i)
                                s1[j] = s1[i];
                ++j;
                }
        } while (s1[i++] != '\0');

}

【问题讨论】:

  • 你的while循环正在做的是迭代字符串s2,但是它只检查第一个字符串的一个值与if,你需要在while中的另一个循环进行检查对于s1 的所有元素,而不仅仅是索引i 处的一个元素。
  • 您似乎在您的函数中完全任意使用ij。也许您需要退后一步,尝试仔细地手工计算出逻辑。至少写一些散文来准确解释你认为你的代码在做什么。而这一年,K&R 在第一次复飞中表现得非常谦虚。
  • @MatteoPinna 最后的 i++ 不是在 while 循环和 if 语句中递增 i 吗?
  • 您的调试打印语句很好。在继续下一个之前,您正在测试每个部分。下一步是学习使用 gdb 之类的调试器,以便您可以单步执行代码并查看变量。
  • @JStone 确实如此,但有什么意义呢?我们以第一次迭代为例,当i=0。所以你正在考虑s2 的第一个元素h。在此之后,您在if 语句中检查s1 (s1[0] = h) 的第一个元素,它们等于您“删除”它。在此之后,您增加i 并再次启动您的while 循环,因此您正在考虑s2 的第二个元素。您只检查了s1 的第一个元素是否等于h,而不是所有元素,明白了吗?

标签: c loops char c-strings function-definition


【解决方案1】:

你的函数没有意义。

while循环根据s2的长度执行

while(s2[i] != '\0')

但是,您使用相同的索引 i 来检查字符串 s1

if(s1[i] == temp)

但字符串s1 通常可以比字符串s2 更短或更大。所以函数可以调用未定义的行为。

s1 中的每个字符也应从字符串s2 的开头开始检查。

可以声明和定义函数(不使用标准 C 字符串函数),如下面的演示程序所示。

#include <stdio.h>

char * squeeze( char s1[], const char s2[] )
{
    if ( *s2 != '\0' )
    {
        size_t i = 0;
        size_t j = 0;

        do
        {
            size_t k = 0;
            while ( s2[k] != '\0' && s2[k] != s1[i] ) ++k;
            
            if ( s2[k] == '\0' )
            {
                if ( j != i ) s1[j] = s1[i];
                ++j;
            }
        } while ( s1[i++] != '\0' );
    }
    
    return s1;
}

int main(void) 
{
    char s1[] = "Hello World!"; 
    const char *s2 = "aeiou";
    
    puts( s1 );
    puts( squeeze( s1, s2 ) );
    
    return 0;
}

程序输出是

Hello World!
Hll Wrld!

【讨论】:

  • 这是一个非常优雅的答案。
  • 感谢弗拉德的回答。我仍然对 if ( j != i ) s1[j] = s1[i]; 感到有些困惑声明虽然..如果你不介意,你(或其他任何人)能解释一下这是做什么的吗?非常感谢你们的所有帮助。这个答案肯定比书中给出的答案更容易理解。我觉得我“几乎”可以得到它。
  • @JStone 你可以写 s1[j++] = s1[i];但是如果 i 等于 j 则不需要将字符复制到自身中。增加 j 来设置下一个唯一字符的下一个位置就足够了。
  • 太棒了!我现在完全明白了。我还接受了斯塔克的上述建议并下载了 gdb,并且现在能够单步执行代码以查看逻辑.. 做得很好的解决方案!非常感谢您为此付出的所有时间和精力。我觉得通过发布这个问题并得到大家的帮助,我确实取得了一些进展。
【解决方案2】:

我使用tmp 缓冲区复制不包含字符。比较简单,可以查一下。

void squeeze(char s1[], char s2[]){
    int i, j, k = 0;
    char* tmp;
    
    // tmp buffer initial size can be maximum s1 length
    tmp = malloc(strlen(s1) + 1);
    
    // loop until s1 character is null
    i = 0;
    while(s1[i] != '\0'){
        // loop until character is found or to the end.
        // break if s2 reached to the end or s1[i] == s2[j]
        j = 0;
        while(s2[j] != '\0' && s2[j] != s1[i]){
            j++;
        }
        
        // if j reached to the end, add into tmp buffer
        if(s2[j] == '\0'){
            // set current character
            tmp[k] = s1[i];
            // increase index
            k++;
        } else {
            printf("Found %c\n", s1[i]);
        }
        
        // next character
        i++;
    }
    // last character must be null
    tmp[k] = '\0';
    
    // tmp copy to s1
    strcpy(s1, tmp);
    
    // free tmp buffer
    free(tmp);
}

【讨论】:

    猜你喜欢
    • 2015-09-30
    • 2017-10-07
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2011-02-22
    • 2015-04-29
    • 1970-01-01
    相关资源
    最近更新 更多