在 trim 函数中有一个 if-check 不能正常工作,为什么?

in trim function there's an if-check not working properly, why?

编辑:我编辑了我的代码,结果如下:

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

char *trim(const char *s) {
    if (s == NULL) {
        return NULL;
    }
    size_t count_1 = 0;
    for (size_t i = 0; s[i] != '[=11=]'; i++) {
        count_1++;
    }
    if (count_1 < 1) {
        return NULL; 
    }
    size_t count_2 = 0;  
    if (isspace(s[0])) {
        count_2++;
    }
    if (isspace(s[count_1 - 1])) {
        count_2++;
    }
    size_t max_length = (count_1 - count_2) + 1u;
    if (max_length >= count_1) {
        return NULL;
    }
    char *str = malloc(max_length);
    if (!str) {
        return NULL;
    }
    for (size_t i = 0; s[i] != '[=11=]'; i++) {
        if (isspace(s[i]) == 0) { // if isspace is false. 
            str[i] = s[i];
        }
    }
    str[count_1 - count_2] = 0;
    return str;
}

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

    free(str);
    return 0;
}

现在,问题来了

    for (size_t i = 0; s[i] != '[=12=]'; i++) {
        if (isspace(s[i]) == 0) { // if isspace is false. 
            str[i] = s[i];
        }

我有一个缓冲区溢出,即使我已经检查了长度。事实上,如果 count_1 等于零,我有一个缓冲区溢出错误,但我已经排除了这种情况,但问题仍然存在。通过逐行调试,我注意到我有一个未定义的行为。


我想尝试简化此练习的建议解决方案,因此我为同一练习编写了另一个代码。

这是原来的答案:

这是最小的可重现代码:

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

char *trim(const char *s) {
    size_t count_1 = 0;
    for (size_t i = 0; s[i] != '[=13=]'; i++) {
        count_1++;
    }
    size_t count_2 = 0;
    if (isspace(s[0])) {
        count_2++;
    }
    if (isspace(s[count_1])) {
        count_2++;
    }
    size_t max_length = (count_1 - count_2) + 1u; 
    if (max_length >= count_1) {
        return NULL; 
    }
    char *str = malloc(max_length); 
    if (!str) {
        return NULL; 
    }
    for (size_t i = 0; s[i] != '[=13=]'; i++) {
        if (isalpha(s[i]) == 0) { // if isalpha is false. 
            str[i] = s[i]; 
        } 
        str[count_1 - count_2] = 0; 
    }
    return str; 
}

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

    free(str); 
    return 0; 
} 

这里是我到目前为止所做的详细解释:

注意:我选择使用 isspace 函数(在 <ctype.h> 中),因为我尝试输入 ' '(即空格),但结果不正确,并且这些 if-checks 不会被评估。 (我用调试器逐行说明了这件事)。

我想我可以避免解释最后的步骤,因为它们是不言自明的,而且我也认为它们不会导致错误。如果我错了,我会编辑这一点。

问题我不知道如何解决它:

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

  • count_1 是字符串的长度,您应该将其更明确地命名为 len
  • 你 return NULL 如果不需要修剪。这是值得怀疑的。在所有情况下,您可能应该 return 字符串的副本,并且在分配失败的情况下仅 return NULL
  • 您只测试字符串开头的 1 个 space 个字符。
  • 您只测试字符串末尾的 1 个 space 个字符。
  • 此外,如果字符串为 " ",则此 space 可能会被计算两次。
  • max_length用词不当:它不是新字符串的长度,而是分配大小,new_size似乎更合适。
  • 在最后一个循环中,您在原始字符串和新字符串中使用相同的索引 i:这是不正确的。您应该使用单独的索引,以便在跳过初始 space.
  • 后可以复制原始字符串中的字符
  • str[count_1 - count_2] = 0; 在循环内是多余的:你应该在循环结束后移动这个语句。
  • 类型 char 的参数值在传递给 <ctype.h> 中定义的函数和宏时应转换为 (unsigned char) 以避免在 char 类型已签名。这些函数仅针对 unsigned char 类型的值(介于 0UCHAR_MAX 之间)和特殊的负值 EOF 定义。这些值是由 getchar()getc() 编辑的 return。

这是修改后的版本:

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

char *trim(const char *s) {
    if (s == NULL) {
        return NULL;
    }
    size_t start, end;
    for (start = 0; isspace((unsigned char)s[start]); start++) {
        continue;
    }
    for (end = start; s[end] != '[=10=]'; end++) {
        continue;
    }
    while (end > start && isspace((unsigned char)s[end - 1])) {
        end--;
    }
    // if you are allowed to use strndup, you can return the new string this way:
    //return strndup(str + start, end - start);

    char *new_str = malloc(end - start + 1);
    if (new_str) {
        size_t j = 0;  // index into the new string
        for (size_t i = start; i < end; i++) {
            new_str[j++] = str[i];
        }
        new_str[j] = '[=10=]';
    }
    return new_str;
}

int main(void) {
    char s[] = " a b ";
    char *str = trim(s);
    printf("trim(\"%s\") -> \"%s\"\n", s, str);
    free(str);
    return 0;
}