字符串复制函数无法正确复制字符串。我的代码有什么问题?

String copy function not copying string properly. What's wrong with my code?

我正在尝试编写一个函数,从字符串中删除 whitesapces 并将其转换为小写。

我下面的代码没有 return 任何东西。为什么?

char *removeSpace(char *st);

int main(void){
    char *x = "HeLLO WOrld ";

    x = removeSpace(x);
    printf("output: %s\n", x);

}

char *removeSpace(char *st)
{
    int c = 0;
    char *s = malloc(sizeof(strlen(st)+1));
    for (int x = 0; x < strlen(st); x++)
    {
        if (st[x] != ' ')
        {
            s[x] = tolower(st[x]);
        }
    }
    st= s;

    st= s;
    return st;
}

char *s = malloc(sizeof(strlen(st)+1));

你有几个嵌套表达式,你在评论线程中完全跳错了方向(我猜是50:50)。

  • strlen(st)是字符串的字符数st

  • strlen(st)+1 是为副本分配的正确字符数

    ...到目前为止看起来不错!

  • sizeof(strlen(st)+1) 是表示该值的 type 所需的字节大小。所以如果 size_t 是一个 4 字节的 unsigned int,这个 sizeof 表达式就是 4.

    此时字符串长度的值被丢弃。

现在,您要为字符串分配足够的字节,但没有足够的字节来将字符串的长度保存为 size_t 值。完全删除 sizeof

哦,还有 - st = s 在这里什么也没做。变量 st 在函数内部是局部的,不会影响外部的任何东西。返回 s 就足够了。

如评论中所述,malloc 语句不必要地使用了 sizeof。您在为新字符串分配字符时也有错误:

s[x] = tolower(st[x]);

您对新字符串 s 使用与旧字符串 st 相同的索引。一旦您删除任何 spaces,这是不正确的。因此,例如,当您复制 hello 时,索引 0 到 4 在两个字符串之间排列,但随后您跳过索引 5 处的 space 然后您想要分配 w 在 st[6] 到 s[5]。这意味着您需要一个单独的索引来跟踪您在目标字符串中的位置。所以你需要类似这段代码的东西,它清理 malloc(),添加缺失的 header 包含,并为输出字符串引入一个新索引:

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

char *removeSpace(char *st);

int main(void){
    char *x = "HeLLO WOrld ";

    x = removeSpace(x);
    printf("output: %s\n", x);

}

char *removeSpace(char *st)
{
    size_t len = strlen(st);
    int newStrIdx = 0;
    char *s = malloc(len+1);
    for (int x = 0; x < len; x++)
    {
        if (st[x] != ' ')
        {
            s[newStrIdx++] = tolower(st[x]);
        }
    }
    s[newStrIdx] = '[=11=]';

    return s;
}

哦,你忘记了 null-terminate 我在最后添加的输出字符串。

对于初学者来说,如果你想创建一个字符串的副本,那么函数声明应该是这样的

char * removeSpace( const char *st);

即原始字符串在函数内没有改变。

当你向函数传递一个字符串文字时

char *x = "HeLLO WOrld ";

x = removeSpace(x);

那么在函数内确实不能更改。任何更改字符串文字的尝试都会导致未定义的行为。

调用malloc时使用的表达式

sizeof(strlen(st)+1)

等同于表达式

sizeof( size_t )

由于函数 strlen 具有 return 类型 size_t

所以这个表达式不会产生源字符串的长度。

此外,无需分配大小与源字符串大小相等的字符串,因为目标字符串的字符数(由于删除了 spaces)比源字符串少得多。

if语句中的赋值

    if (st[x] != ' ')
    {
        s[x] = tolower(st[x]);
    }

在表达式 s[x] 中使用了无效索引。因此,目标字符串将包含未初始化字符的间隙。

终止零字符 '[=23=]' 也没有附加到目标字符串

考虑到白色 space 字符集包括其他字符,例如制表符 '\t' 除了 space 字符 ' '

函数可以这样定义。

char * removeSpace( const char *st )
{
    size_t n = 0;

    for ( const char *src = st; *src; ++src )
    {
        if ( !isspace( ( unsigned char )*src ) ) ++src;
    }

    char *result = malloc( n + 1 );
    result[n] = '[=15=]';        
    
    for ( char *dsn = result; *st; ++st )
    {
        if ( !isspace( ( unsigned char )*st ) )
        {
            *dsn++ = tolower( ( unsigned char )*st );
        }
    }

    return result;
}

而且函数可以这样调用

char *st = "HeLLO WOrld ";

char *dsn = removeSpace( st );

puts( dsn );

free( dsn );

这是一个演示程序。

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

char * removeSpace( const char *st )
{
    size_t n = 0;

    for ( const char *src = st; *src; ++src )
    {
        if ( !isspace( ( unsigned char )*src ) ) ++src;
    }

    char *result = malloc( n + 1 );
    result[n] = '[=17=]';        
    
    for ( char *dsn = result; *st; ++st )
    {
        if ( !isspace( ( unsigned char )*st ) )
        {
            *dsn++ = tolower( ( unsigned char )*st );
        }
    }

    return result;
}

int main(void) 
{
    char *st = "HeLLO WOrld ";

    char *dsn = removeSpace( st );

    puts( dsn );

    free( dsn );

    return 0;
}

它的输出是

helloworld