【问题标题】:C function for maniplulating string用于操作字符串的 C 函数
【发布时间】:2021-09-06 20:29:24
【问题描述】:

我已经编写了这个练习,它应该删除出现在第二个字符串中的第一个参数字符串中的所有字符。但结果是以下参数的分段错误。谁能向我解释我错过了什么?

#include <stdio.h>

void squeez(char s1[], char s2[])
{
  int i, j, k, match;
  while (s1[i] != '\0') {
    match = 0;
    for (k = 0; s2[k] != '\0'; ++k) {
      if (s1[i] == s2[k]) {
    match = 1;
    break;
      }
    }
    if (match) {
      i++;
    } else {
      s1[j++] = s1[i++];
    }
  }
  s1[j] = '\0';
}

int main()
{
  char s[] = "asdsffffsffsk";
  char x[] = "sf";
  squeez(s, x);
  printf("%s %s", s, x);
  return 0;
}

【问题讨论】:

  • 循环调用strcspn()
  • i, j 未初始化
  • 一个好的开始是将i初始化为0。实际上,它的值是未知的,所以谁知道您要在内存中的哪个位置建立索引? j 也是如此。难怪你会遇到分段错误。
  • 这似乎是学习如何使用 调试器 捕捉崩溃并在代码中定位它们发生的时间和位置的最佳时机。当您发现崩溃时,您还可以检查所有相关变量的值以确保它们正常(如数组索引在范围内)。
  • 在数组中使用索引比递增s1 复杂得多。熟悉指针算法;它应该是你最好的朋友。

标签: c char c-strings


【解决方案1】:

对于初学者来说,函数应该以下列方式声明

char * squeez( char s1[], const char s2[] );

即第二个参数应该有限定符const,因为这个参数指定的字符串在函数中没有改变。

该函数应遵循 C 标准字符串函数的一般约定,并返回指向结果字符串的指针。

在函数内,变量ij 未初始化并且具有不确定的值。所以即使是第一个while循环

int i, j, k, match;
while (s1[i] != '\0') {
// ...

调用未定义的行为。

您应该使用size_t 类型而不是这些变量中的int 类型,因为int 类型可能不够大,无法存储字符串的长度。

您应该在使用它们的最小范围内声明变量。

保持您对函数定义的态度,它可以如下面的演示程序所示。

#include <stdio.h>

char * squeez( char s1[], const char s2[] )
{
    size_t i = 0, j = 0;
    
    while ( s1[i] != '\0' ) 
    {
        int match = 0;
        
        for ( size_t k = 0; !match && s2[k] != '\0'; ++k ) 
        {
            if ( s1[i] == s2[k] ) match = 1;
        }

        if ( !match ) s1[j++] = s1[i];
        i++;
    }
    
    s1[j] = '\0';
    
    return s1;
}

int main(void) 
{
    char s[] = "asdsffffsffsk";
    char x[] = "sf";
    
    puts( squeez( s, x ) );

    return 0;
}

程序输出是

adk

由于变量i 没有在while 循环之外使用,那么while 循环可以替换为一个for 循环,其中将声明变量i。例如

char * squeez( char s1[], const char s2[] )
{
    size_t j = 0;
    
    for ( size_t i = 0; s1[i] != '\0'; i++ ) 
    {
        int match = 0;
        
        for ( size_t k = 0; !match && s2[k] != '\0'; ++k ) 
        {
            if ( s1[i] == s2[k] ) match = 1;
        }

        if ( !match ) s1[j++] = s1[i];
    }
    
    s1[j] = '\0';
    
    return s1;
}

【讨论】:

  • 谢谢!在我看来,您的大部分观点都是 C 风格的问题。如果您对自己的决定发表更多评论,那就太好了,例如为什么函数要返回指向 s1 参数的指针,即使函数正在就地修改该字符串?
  • @Student C 字符串函数采用此约定。例如考虑函数 strcpy。该函数返回指向结果字符串的指针。在这种情况下,您可以在表达式中使用这样的函数。
【解决方案2】:

我注意到 i 和 j 没有初始化。事实上,您的代码没有我提出的问题是可行的。这是我试过的代码。

#include <stdio.h>

void squeez(char s1[], char s2[])
{
    int index1 = 0, position = index1, index2 = 0;
    int match = 0;
    while (s1[index1] != '\0')
    {
        match = 0;
        for (index2 = 0; s2[index2] != '\0'; index2++)
        {
            if (s1[index1] == s2[index2])
            {
                match = 1;
                break;
            }
        }
        if (match)
            index1++;
        else
            s1[position++] = s1[index1++];
    }
    s1[position] = '\0';
}

int main()
{
    char s[] = "asdsffffsffsk";
    char x[] = "sf";
    squeez(s, x);
    printf("%s %s", s, x);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2021-12-19
    • 2018-04-02
    • 2020-09-04
    • 1970-01-01
    相关资源
    最近更新 更多