strcat

时间:2017-07-25 15:42:16

标签: c segmentation-fault strcat

我最近开始学习C语言并且反复遇到一个错误,其中从<string.h>模块调用strcat函数会导致分段错误。我在网上搜索了答案,包括this stackoverflow post,但没有成功。我认为这个社区可能对这个问题有更个人的了解,因为一般的解决方案似乎不起作用。可能是用户错误,可能是代码的个人问题。看一看。

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

char * deblank(const char str[]){
    char *new[strlen(str)];
    char *buffer = malloc(strlen(new)+1);
    for (int i=0; i<strlen(*str); i++){
        if(buffer!=NULL){
            if(str[i]!=" "){
                strcat(new,str[i]); //Segmentation fault
            }
        }
    }
    free(buffer);
    return new;
}

int main(void){
    char str[] = "This has spaces in it.";
    char new[strlen(str)];
    *new = deblank(str);
    puts(new);
}

我已经对我已追溯到细分故障的行发表了评论。以下是一些Java来解释这个C代码。

public class deblank {
    public static void main(String[]args){
        String str = "This has space in it.";
        System.out.println(removeBlanks(str));
    }

    public static String removeBlanks(String str){
        String updated = "";
        for(int i=0; i<str.length(); i++){
            if(str.charAt(i)!=' '){
                updated+=str.charAt(i);
            }
        }
        return updated;
    }
}

非常感谢对此错误的任何见解。请指出错别字......我已经知道要制作错字。感谢。

6 个答案:

答案 0 :(得分:2)

所以,不确定这是否对您有所帮助,但是与您的Java代码相同的C代码将如下所示:

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

static char *removeBlanks(const char *str)
{
    char *result = malloc(strlen(str) + 1);
    if (!result) exit(1);
    const char *r = str;
    char *w = result;
    while (*r)
    {
        // copy each character except when it's a blank
        if (*r != ' ') *w++ = *r;
        ++r;
    }
    *w = 0; // terminate the result to be a string (0 byte)
    return result;
}

int main(void)
{
    const char *str = "This has spaces in it.";
    char *new = removeBlanks(str);
    puts(new);
    free(new);
    return 0;
}

我建议命名变量new ...如果你想使用C ++,这是一个保留的关键字。

答案 1 :(得分:2)

好的,我们这样做。

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

char * deblank(const char str[]){
    char *new[strlen(str)];

^此行创建一个指针数组,而不是字符串。

    char *buffer = malloc(strlen(new)+1);

malloc未声明。缺少#include <stdlib.h>。此外,您应该在这里检查分配失败。

strlen(new)是类型错误。 strlen需要char *,但new是(或更确切地说是评估)char **

    for (int i=0; i<strlen(*str); i++){

strlen(*str)是类型错误。 strlenchar *,但*strchar(即单个字符)。

i<strlen(...)值得怀疑。 strlen返回size_t(无符号类型),而iint(已签名,可能太小)。

在循环中调用strlen是低效的,因为它必须遍历整个字符串才能找到结束。

        if(buffer!=NULL){

这是一个检查分配失败的奇怪地方。此外,您不在任何地方使用buffer,那么为什么要创建/检查它呢?

            if(str[i]!=" "){

str[i]!=" "是类型错误。 str[i]char" "是(或更确切地说是评估)char *

                strcat(new,str[i]); //Segmentation fault

这是类型错误。 strcat有两个字符串(char *),但newchar **str[i]char。此外,strcat的第一个参数必须是有效字符串,但new未初始化。

            }
        }
    }
    free(buffer);
    return new;

new是此函数中的本地数组。你正在返回它的第一个元素的地址,这是没有意义的:一旦函数返回,它的所有局部变量都消失了。你在这里返回一个无效指针。

此外,这是类型错误:deblank被声明为返回char *但实际上返回char **

}

int main(void){
    char str[] = "This has spaces in it.";
    char new[strlen(str)];
    *new = deblank(str);

这是类型错误:*newchardeblank返回char *

    puts(new);

puts接受一个字符串,但此时new基本上是垃圾。

}

答案 2 :(得分:1)

我尝试在启用警告的情况下编译,这里有一些你应该修复。

  • 您需要加入stdlib.h
  • char *new[strlen(str)]创建一个char*而不是char的数组,因此不是一个字符串。将其更改为char new[strlen(str)]
  • 要检查str[i]是否为空格,请将其与空格字符' '进行比较,而不是唯一字符为空格" "的字符串。因此,将其更改为str[i]!=' '
  • strcat将字符串作为第二个参数,而不是字符,就像您使用str[i]一样。

另外,您使用buffer进行了什么?

另一个错误是,您可能认为未初始化的数组采用零值。 new数组具有随机值,而不是零/空。 strcat连接两个字符串,因此它会尝试将字符串放在第一个参数new末尾的第二个参数中。字符串的“结尾”是空字符。程序在new中搜索它可以找到的第一个空字符,当它找到null时,它开始从那里写第二个参数。

但由于new未初始化,程序可能无法在new中找到空字符,并且会继续搜索newstrlen(str)的长度,继续搜索未分配的内存。这可能是导致分段错误的原因。

答案 3 :(得分:1)

你不能像你一样使用strcat,它的目的是在另一个给定的C字符串的末尾处连接一个C字符串。 str[i]是char而不是C字符串(请记住,C字符串是连续的字符序列,最后一个是NUL字节)。

您也无法将字符串与标准比较运算符进行比较,如果您确实需要比较字符串,那么它就有strcmp函数。但是你可以将字符与标准运算符进行比较,因为char只是一种整数类型。

这应该可以解决问题:

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

char * deblank(const char str[]) {
    char *buffer = malloc(strlen(str)+1); // allocate space to contains as much char as in str, included ending NUL byte
    for (int i=0, j=0; i<strlen(str)+1; i++) { // for every char in str, included the ending NUL byte
      if (str[i]!=' ') { // if not blank
        buffer[j++] = str[i]; // copy
      }
    }
    return buffer; // return a newly constructed C-string
}

int main(void){
    char str[] = "This has spaces in it.";
    char *new = deblank(str);
    puts(new);
    free(new); // release the allocated memory
}

答案 4 :(得分:1)

这项任务可以有三种方法。

第一个是更新字符串“就地”。在这种情况下,函数可以看起来像以下方式

except:

程序输出

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

char * deblank( char s[] )
{
    size_t i = 0;

    while ( s[i] and not isblank( s[i] ) ) ++i;

    if ( s[i] )
    {
        size_t j = i++;
        do
        {
            if ( not isblank( s[i] ) ) s[j++] = s[i];
        } while( s[i++] );
    }

    return s;
}

int main(void) 
{
    char s[] = "This has spaces in it.";

    puts( s );

    puts( deblank( s ) );

    return 0;
}

另一种方法是将源字符串复制到跳过空格的目标字符数组中。

在这种情况下,该函数将有两个参数:源数组和目标数组。并且目标数组的大小必须等于源数组的大小,因为通常源数组不能有空格。

This has spaces in it.
Thishasspacesinit.

程序输出与上面显示的相同。

注意这个声明

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

char * deblank( char *s1, const char *s2 )
{
    char *t = s1;

    do 
    {
        if ( not isblank( *s2 ) ) *t++ = *s2;
    } while ( *s2++ );

    return s1;
}

int main(void) 
{
    char s1[] = "This has spaces in it.";
    char s2[sizeof( s1 )];

    puts( s1 );

    puts( deblank( s2, s1 ) );

    return 0;
}

目标字符串的大小通常不应小于源字符串的大小。

最后,第三种方法是在函数内部动态创建一个数组,并从函数返回指向数组第一个元素的指针。

在这种情况下,首先需要计算源阵列中用于分配具有适当大小的目标阵列的空白数。

要使用char s2[sizeof( s1 )]; malloc功能,您需要包含以下标题

free

该功能可以在演示程序中显示。

#include <stdlib.h>

程序输出与前两个程序相同。

至于标准的C函数#include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <iso646.h> char * deblank( const char *s ) { size_t n = 1; /* one byte reserved for the terminating zero character */ for ( const char *t = s; *t; ++t ) { if ( not isblank( *t ) ) ++n; } char *s2 = malloc( n ); if ( s2 != NULL ) { char *t = s2; do { if ( not isblank( *s ) ) *t++ = *s; } while ( *s++ ); } return s2; } int main(void) { char s1[] = "This has spaces in it."; char *s2 = deblank( s1 ); puts( s1 ); if ( s2 ) puts( s2 ); free( s2 ); return 0; } ,那么它就是两个字符串。

例如

strcat

目标数组(在本例中为#include <stdio.h> #include <string.h> int main(void) { char s1[12] = "Hello "; char *s2 = "World"; puts( strcat( s1, s2 ) ); return 0; } )必须有足够的空间才能附加字符串。

C标准中还有另一个C函数s1,它允许将单个字符附加到字符串。例如,上述程序可以通过以下方式重写

strncat

但是对原始任务使用这种方法效率不高,因为每次调用函数时,都必须在源字符串中找到要附加字符的终止零。

答案 5 :(得分:1)

你可以递归地尝试

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

void deblank(const char* str, char *dest) {
    if (!*str) {*dest = '\0';return;}

    // when we encounter a space we skip
    if (*str == ' ') {
      deblank(str+1, dest);
      return;
    }

    *dest = *str;
    deblank(str+1, dest+1);
}

int main(void) {
    const char *str = "This has spaces in it.";
    char *output    = malloc(strlen(str)+1);
    deblank(str, output);
    puts(output);
    free(output);
}