断言在字符串数组比较中失败

Assert is failing in a string array comparison

在我的这部分代码中,我删除了 string1 的空格并将结果复制到 string2

char * remove_blank_spaces(char * string1) {
   char * string2 = malloc(sizeof(string1));
   int index = 0;

   for (int i = 0; string1[i] != 0; i++) {
      if(string1[i] != ' ') {
         //printf("i: %d\n", i);
         //printf("c2: %c\n", string1[i]);
         string2[index] = string1[i];
         index++;
      }
   }
   string2[index] = '[=10=]';

   printf("string2: %s\n", string2);
   return string2;
}

我检查结果:

assert(remove_blank_spaces("a  b") == "ab");  // Edit: here is the error!

我收到一个错误:Assertion failed!Expression: remove_blank_spaces("a b") == "ab"

我比较了 Virtual-C 中的字符串,它们看起来是一样的。 为什么断言失败?

因为你的代码有问题。

首先,您在指针上使用 sizeof,它给出指针的大小而不是字符串的大小。解决方法是使用 strlen 加上空字符的一个字符的大小,因为它是空字符终止的。

我认为的第二个也是最后一个是在比较您使用的字符串 == 时,这将比较 C 中的字符串指针而不是字符串。解决方案是使用 strcmp.

那么代码将如下所示

char * remove_blank_spaces(char * string1) {
   char * string2 = malloc(strlen(string1) + sizeof(char)); // < -- one change here, was sizeof(string1)
   int index = 0;

   for (int i = 0; string1[i] != 0; i++) {
      if(string1[i] != ' ') {
         //printf("i: %d\n", i);
         //printf("c2: %c\n", string1[i]);
         string2[index] = string1[i];
         index++;
      }
   }
   string2[index] = '[=10=]';

   printf("string2: %s\n", string2);
   return string2;
}

断言将如下所示:

assert(strcmp(remove_blank_spaces("a b"), "ab") == 0);

您的代码有一个错误:malloc 分配不足 space,这会导致在尝试访问未分配的内存时出现未定义的行为。

断言也失败了,因为您是通过 == 比较指针,而不是通过 strcmp.

比较 C 字符串

此外,我建议进行两处更改:

  • 不要混淆计算和输出。 Return这个值,不要printf在函数里面。
  • 使用描述性的并正确名称。这需要考虑上下文。例如,index 通常可以是一个好名字,但在您的情况下,不清楚 您指的是哪个 索引,这会引发错误,其中 index用于索引错误的变量。至于“正确”的名字,你所说的“空白space”通常被称为“白色space”。

为了改进第二点,我建议实际更改实现,而不是使用第二个 index 变量,使用指针迭代输出。还有其他可能性,但这种可能性的优点是不可能意外使用错误的变量进行索引。

综合起来,我们得到

char *remove_whitespace(const char *str) {
    char *result = malloc(strlen(str) + 1);
    char *out = result;

    for (size_t i = 0; str[i] != '[=10=]'; i++) {
       if (str[i] != ' ') {
           *out++ = str[i];
       }
    }
    *out = '[=10=]';
    return result;
}

我们还可以取消 i 循环计数器。不幸的是,结果是 less 可读,而不是更多,因为我们需要在循环结束时递增 str,这会给我们留下难看的 for (; *str != '[=20= ]'; str++)循环结构。

对于初学者这个函数声明

char * remove_blank_spaces(char * string1) {

不正确,只会让函数的用户感到困惑。如果在函数内创建一个新的字符数组,则参数应具有限定符 const.

char * remove_blank_spaces( const char * string1) {

否则该函数应更改原始字符串 "in-place"。

这次通话

char * string2 = malloc(sizeof(string1));

也是不正确的。我想你的意思是

char * string2 = malloc( strlen( string1 ) + 1 );

但即使是这个调用也不是很好,因为结果字符串可能比原始字符串少很多。

所以首先你应该统计结果字符串中的字符数,然后才分配内存。

这个断言也不正确

assert(remove_blank_spaces("a  b") == "ab");

这个表达式中有两个字符串的比较地址:第一个是函数返回的字符串,第二个是字符串字面量。

就算你会写这样的表达式

assert( "ab" == "ab");

表达式的值可以等于逻辑 true 或 false,具体取决于编译器选项,该选项指定相等的字符串文字是作为一个字符串文字存储还是占用不同的内存范围。

你应该改写

assert( strcmp( remove_blank_spaces("a  b"), "ab" ) == 0 );

考虑到在 if 语句中考虑制表符 '\t' 也是合理的

if(string1[i] != ' ' && string1[i] != '\t') {

或者您可以使用标准函数 isblank

这是一个演示程序

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

char * remove_blank_spaces( const char *s ) 
{
    size_t n = 0;

    for ( size_t i = 0; s[i] != '[=18=]'; i++ )
    {
        if ( !isblank( ( unsigned char )s[i] ) ) ++n;
    }

    char *result = malloc( n + sizeof( ( char )'[=18=]' ) );

    char *p = result;

    do
    {
        if ( !isblank( ( unsigned char )*s ) )
        {
            *p++ = *s;
        }
    } while ( *s++ != '[=18=]' );

    return result;
}

int main(void) 
{
    const char *s1 = "a b";
    char *s2 = remove_blank_spaces( s1 );

    assert( strcmp( s1, s2 ) == 0 );

    puts( s2 );

    free( s2 );

    return 0;
}

程序输出为

ab

注意这一点,而不是其他答案中显示的类型 int 您应该对变量 indexi 使用类型 size_t 因为它是用于字符串长度和索引以及函数 malloc 的类型。类型 int 不够大,无法存储字符串的大小。

如果你确实想像这样声明函数

char * remove_blank_spaces( char *s ) 

也就是说,当参数没有限定符 const 时,您不应在函数内动态分配新的字符数组,函数本身看起来会简单得多。

这是一个演示程序。

#include <stdio.h>
#include <assert.h>
#include <string.h>

char * remove_blank_spaces( char *s ) 
{
    char *destination = s;
    char *source = s;

    do
    {
        if ( *source != ' ' && *source != '\t' )
        {
            *destination++ = *source;
        }
    } while ( *source++ != '[=21=]' );

    return s;
}

int main(void) 
{
    char s[] = "a b";

    remove_blank_spaces( s );

    assert( strcmp( s, "ab" ) == 0 );

    puts( s );

    return 0;
}

它的输出是

ab