c语言 - 为什么 malloc 不能与 strcpy 一起工作?


char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}


int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%sn", input);
free(input);
return 0;
}

我不知道为什么每次我尝试运行它时,它总是说未初始化的变量并坚持在 strcpy 行和 printf 行中。

基本上这个函数是获取一个字符串和一个字符,并从字符串中删除该字符(因为我正在学习 malloc,所以这就是我这样编写函数的原因)。

在 while 循环之后执行以下操作:

copy[j] = '';

NULL-终止你的字符串;这样它就可以处理来自<string.h>的方法,这些方法假定字符串是 NUL 终止的。


PS:你应该看到的一个警告是无论如何都不在你的函数中返回copy,因为现在如果if语句的条件是错误的,你的函数将不会返回有效的东西,所以添加这个:

return copy;

在函数的末尾(现在已通过编辑进行更正)。

除此之外,您仍然应该得到的唯一警告是针对未使用的参数main(),没有别的:

prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~

当您将字节从str复制到copy时,您不会在末尾添加终止空字节。 因此,strcmp读取的复制字符进入单元化内存,可能超过分配的内存块的末尾。 这将调用未定义的行为。

while循环之后,将终止空字节添加到copy

此外,如果末尾的if块为 false,则永远不会返回值。 您需要为此返回一些内容,可能是复制的字符串。

char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
//  add terminating null byte
copy[j] = '';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}

你从未初始化过输入,一些编译器没有注意到, 该值永远不会在行之前使用

input = removeChar(str, 'g');

在您的代码中。因此,他们发出诊断只是为了确定。

strcpy(str, copy)

卡在你的代码中,因为副本从来没有一个结束的 0 字节和 所以取决于你的记忆的非确定性内容在 内存备份副本的分配时刻,strcpy 多长时间 将运行,如果您最终获得 SIGSEGV(或类似)。

strcpy将循环,直到在您的内存中找到 0 字节。

对于从字符串中删除字符的初学者来说,不需要动态创建字符数组,然后将该数组复制到原始字符串中。

您应该编写一个确实从字符串中删除指定字符的函数,或者编写一个基于源字符串(不包括指定字符)创建新字符串的函数。

这只是一个糟糕的设计,只会让用户感到困惑。那就是函数太复杂了,使用了冗余函数,如mallocstrlenstrcmpstrcpy。事实上,它有一个不明显的副作用。此外,字符串的长度使用了不正确的类型int而不是类型size_t

至于你的函数实现,那么你忘了将终止零'\0'附加到动态分配数组中构建的字符串中。

如果您确实想从字符串中删除字符,则该函数可以看起来像演示程序中显示的那样。

#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}

程序输出为

Input string
Input strin

如果您正在学习malloc函数并想使用它,则在任何情况下都应尝试实现正确的设计。

若要使用malloc可以编写一个函数,该函数基于源字符串(不包括指定字符)创建新字符串。例如

#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}

程序输出将与上述相同。

Input string
Input strin

注意函数声明

char * remove_copy_char(const char *s, char c);
^^^^^^

在这种情况下,源字符串可以是字符串文本。

char *str = "Input string";

最新更新