Функция разделения строк - PullRequest
1 голос
/ 19 февраля 2011

Я кодирую функцию разделения, это код:

#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 MUNDOCOMO "программа работает правильно ...

Как мне ее решить?

Ответы [ 3 ]

2 голосов
/ 19 февраля 2011

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 голосов
/ 19 февраля 2011

Научитесь использовать 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 и получаете доступ к таблице [i], которая не выделяется. Например, при первом входе в цикл вы перераспределяете таблицу из 1 символа * (чтобы не увеличивать ее) и получаете доступ ко второму элементу таблицы. при втором входе в цикл вы увеличиваете размер массива до 2 и получаете доступ к третьему элементу /

вторая ошибка в строке 35 означает, что в вашей таблице MILISTA есть некоторые части, которые не инициализированы из-за неправильного поведения первого цикла.

1 голос
/ 19 февраля 2011

Вы не должны изменять содержимое argv (обратите внимание, что strtok изменит переданную строку).

Остальная часть функции почти правильная, однако вы вызываете realloc, чтобы освободить место для (i+1) элементов, в то время как i по-прежнему равно 0. Таким образом, в основном вы выделяете пространство на один указатель меньше, чем нужно. Просто переместите i++; в начало цикла, и все в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...