拆分字符串功能

时间:2011-02-19 14:23:29

标签: c

我正在编写分割函数,这是代码:

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

char **split ( const char *s1, const char *s2) {

    char **lista;
    char *aux = s1;
    char *token_Ptr;
    int i = 0;
    
    lista = (char **) malloc (sizeof (char *));
    token_Ptr = strtok(aux, s2);
    lista[i] = token_Ptr;
    while(token_Ptr != NULL)
    {
        lista = (char **)realloc(lista, sizeof(char*) * (i + 1));
        token_Ptr = strtok(NULL, s2);
        i++;
        lista[i] = token_Ptr;
    }
    return lista;
}

int main ( int argc , char *argv[]) {

    char **MILISTA;
    int i;

    if (argc==2) {
        printf ("Cadena: '%s'\n",argv[1]);
        MILISTA= split(argv[1]," ");
        i=0;
        puts("----------------TOKENS------------");
        while (MILISTA[i]!=NULL) {
            printf("%s, " , MILISTA[i++]);
        }
        printf("\n");
        puts("----------------FIN---------------");
    }
    return 0;
}

但我有一些错误:

facu@linux:~/projects/spliting/bin/Debug$ ./spliting "HOLA MUNDO COMO s"
Cadena: 'HOLA MUNDO COMO s'
*** glibc detected *** ./spliting: realloc(): invalid next size: 0x09e12008 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0x17c501]
/lib/libc.so.6(+0x71c6d)[0x181c6d]
/lib/libc.so.6(realloc+0xe3)[0x181f53]
./spliting[0x8048573]
./spliting[0x80485fa]
/lib/libc.so.6(__libc_start_main+0xe7)[0x126ce7]
./spliting[0x8048471]
======= Memory map: ========
00110000-00267000 r-xp 00000000 08:06 8526       /lib/libc-2.12.1.so
00267000-00269000 r--p 00157000 08:06 8526       /lib/libc-2.12.1.so
00269000-0026a000 rw-p 00159000 08:06 8526       /lib/libc-2.12.1.so
0026a000-0026d000 rw-p 00000000 00:00 0 
00573000-0058d000 r-xp 00000000 08:06 251        /lib/libgcc_s.so.1
0058d000-0058e000 r--p 00019000 08:06 251        /lib/libgcc_s.so.1
0058e000-0058f000 rw-p 0001a000 08:06 251        /lib/libgcc_s.so.1
0065a000-0065b000 r-xp 00000000 00:00 0          [vdso]
007f1000-00815000 r-xp 00000000 08:06 8577       /lib/libm-2.12.1.so
00815000-00816000 r--p 00023000 08:06 8577       /lib/libm-2.12.1.so
00816000-00817000 rw-p 00024000 08:06 8577       /lib/libm-2.12.1.so
00c2d000-00d0c000 r-xp 00000000 08:06 660319     /usr/lib/libstdc++.so.6.0.14
00d0c000-00d10000 r--p 000de000 08:06 660319     /usr/lib/libstdc++.so.6.0.14
00d10000-00d11000 rw-p 000e2000 08:06 660319     /usr/lib/libstdc++.so.6.0.14
00d11000-00d18000 rw-p 00000000 00:00 0 
00e86000-00ea2000 r-xp 00000000 08:06 8518       /lib/ld-2.12.1.so
00ea2000-00ea3000 r--p 0001b000 08:06 8518       /lib/ld-2.12.1.so
00ea3000-00ea4000 rw-p 0001c000 08:06 8518       /lib/ld-2.12.1.so
08048000-08049000 r-xp 00000000 08:08 262453     /home/facu/projects/spliting/bin/Debug/spliting
08049000-0804a000 r--p 00000000 08:08 262453     /home/facu/projects/spliting/bin/Debug/spliting
0804a000-0804b000 rw-p 00001000 08:08 262453     /home/facu/projects/spliting/bin/Debug/spliting
09e12000-09e33000 rw-p 00000000 00:00 0          [heap]
b7700000-b7721000 rw-p 00000000 00:00 0 
b7721000-b7800000 ---p 00000000 00:00 0 
b7870000-b7873000 rw-p 00000000 00:00 0 
b7888000-b788b000 rw-p 00000000 00:00 0 
bf834000-bf855000 rw-p 00000000 00:00 0          [stack]
Abortado

如果我只解析:“HOLA MUNDO COMO”程序正确运行......

我该如何解决?

3 个答案:

答案 0 :(得分:2)

学习使用valgrind。这是诊断这类错误最有用的工具之一。

$valgrind ./a.out "HOLA MUNDO COMO s"
==4949== Memcheck, a memory error detector
==4949== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==4949== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==4949== Command: ./a.out HOLA\ MUNDO\ COMO\ s
==4949== 
Cadena: 'HOLA MUNDO COMO s'
==4949== Invalid write of size 8
==4949==    at 0x40070B: split (a.c:20)
==4949==    by 0x40076B: main (a.c:32)
==4949==  Address 0x518a098 is 0 bytes after a block of size 8 alloc'd
==4949==    at 0x4C245E2: realloc (vg_replace_malloc.c:525)
==4949==    by 0x4006DC: split (a.c:17)
==4949==    by 0x40076B: main (a.c:32)
==4949== 
----------------TOKENS------------
==4949== Conditional jump or move depends on uninitialised value(s)
==4949==    at 0x4007BF: main (a.c:35)

这件事说的是,在第20行,你试图在表格结束后写下指针。

这是真的:你分配一个大小为i + 1的表,然后你增加i并访问未分配的table [i]。例如,第一次进入循环时,重新分配一个包含1个字符*的表(因此您不会增长它),并且您可以访问表的第二个元素。第二次进入循环时,将数组增大到2,然后访问第三个元素/

第35行的第二个错误意味着您的MILISTA表中有一些部分由于第一个循环的错误行为而未初始化。

答案 1 :(得分:2)

strtok修改源字符串。您无法修改参数字符串(它是只读的)。将原始字符串复制到另一个字符串中当你重新分配时,而不是+1使用+2(当i = 0时,你已经有了一个元素)。

此:

char **split ( const char *s1, const char *s2) {

    char **lista;
    char *aux = (char*)malloc(strlen(s1) + 1);
    strcpy(aux, s1);
    char *token_Ptr;
    int i = 0;

    lista = (char **) malloc (sizeof (char *));
    token_Ptr = strtok(aux, s2);
    lista[i] = token_Ptr;
    i++;
    while(token_Ptr != NULL)
    {
        lista = (char **)realloc(lista, sizeof(char*) * (i + 1));
        token_Ptr = strtok(NULL, s2);
        lista[i] = token_Ptr;
        i++;
    } 
    return lista;
}

你有2个免费指针: free(lista [0])和free(lista)。

此功能不好,因为它分配内存。一个函数很少应该分配内存。不,这个问题没有任何解决办法:-)你必须小心释放分配的内存。

答案 2 :(得分:1)

您不应更改argv的内容(请注意strtok将修改已传递的字符串。)

函数的其余部分几乎是正确的,但是您调用realloc(i+1)元素腾出空间,而i仍为0.所以基本上你是为一个指针分配空间不到需要。只需将i++;移动到循环的开头,一切都很好。