Je travaille sur une fonction, qui doit prendre un tableau de caractères dynamique, le séparer par des espaces et mettre chaque mot dans un tableau de tableaux de caractères. Voici le code:

char** parse_cmdline(const char *cmdline)
{
    char** arguments = (char**)malloc(sizeof(char));
    char* buffer;
    int lineCount = 0, strCount = 0, argCount = 0;
    int spaceBegin = 0;
    while((cmdline[lineCount] != '\n'))
    {
        if(cmdline[lineCount] == ' ')
        {
            argCount++;
            arguments[argCount] = (char*)malloc(sizeof(char));
            strCount = 0;
        }
        else
        {
            buffer = realloc(arguments[argCount], strCount + 1);
            arguments[argCount] = buffer;
            arguments[argCount][strCount] = cmdline[lineCount];
            strCount++;
        }
        lineCount++;
    }
    arguments[argCount] = '\0';
    free(buffer);
    return arguments;   
}

Le problème est que quelque part en cours de route, j'obtiens une erreur de segmentation et je ne sais pas exactement où. De plus, cette version actuelle de la fonction suppose que la chaîne ne commence pas par un espace, c'est-à-dire pour la version suivante, je peux gérer cela, mais je ne trouve pas la raison du seg. faute

1
Reaper9806 3 janv. 2016 à 22:00

4 réponses

Meilleure réponse

Ce code n'est sûrement pas ce que vous vouliez:

char** arguments = (char**)malloc(sizeof(char));

Il alloue un bloc de mémoire suffisamment grand pour un char, et définit une variable de type char ** (arguments) pour pointer vers lui. Mais même si vous vouliez seulement assez d'espace dans arguments pour un seul char *, ce que vous avez alloué n'est pas suffisant (pas sur n'importe quel système C que vous êtes susceptible de rencontrer, de toute façon). Ce n'est certainement pas assez long pour plusieurs pointeurs.

Supposons que les pointeurs soient en effet plus larges que les char s simples sur votre système C, votre programme invoque un comportement indéfini dès qu'il déréférence arguments. Un défaut de segmentation est l'un des résultats les plus probables.

Le moyen le plus simple est probablement de scanner la chaîne d'entrée deux fois: une fois pour compter le nombre d'arguments individuels, afin que vous puissiez allouer suffisamment d'espace pour les pointeurs, et encore une fois pour créer les chaînes d'arguments individuelles et enregistrer des pointeurs vers eux dans votre tableau.

Notez également que la valeur de retour ne contient aucune information accessible sur la quantité d'espace allouée ou, par conséquent, sur le nombre de chaînes d'arguments que vous avez extraites. L'approche habituelle de ce genre de problème est d'allouer de l'espace pour un pointeur supplémentaire et de définir ce dernier pointeur sur NULL en tant que sentinelle. Cela ressemble beaucoup, mais pas la même chose, à l'utilisation d'un char nul pour marquer la fin d'une chaîne en C.

Modifié pour ajouter:

L'allocation que vous souhaitez pour arguments ressemble plus à ceci:

arguments = malloc(sizeof(*arguments) * (argument_count + 1));

Autrement dit, allouez de l'espace pour un objet de plus qu'il n'y a d'arguments, chaque objet ayant la taille du type d'objet vers lequel arguments est censé pointer. La valeur de arguments n'est pas accédée par sizeof, donc peu importe qu'elle soit indéterminée à ce stade.

Modifié pour ajouter:

L'appel free() à la fin est également problématique:

free(buffer);

À ce stade, la variable buffer pointe vers le même bloc alloué que le dernier élément de arguments pointe vers (ou est destiné à pointer vers). Si vous le libérez, alors tous les pointeurs vers cette mémoire sont invalides, y compris celui que vous êtes sur le point de renvoyer à l'appelant. Vous n'avez pas besoin de libérer buffer à ce stade, pas plus que ce dont vous aviez besoin pour le libérer après l'une des autres allocations.

1
John Bollinger 3 janv. 2016 à 19:28

C'est probablement pourquoi vous avez une erreur de segmentation:

Dans char** arguments = (char**)malloc(sizeof(char));, vous avez utilisé malloc (sizeof (char)), cela alloue de l'espace pour un seul octet (assez d'espace pour un char). Ce n'est pas suffisant pour contenir un seul char* dans arguments.

Mais même si c'était dans un système, arguments[argCount] ne lit que la mémoire allouée pour argCount = 0. Pour les autres valeurs de argCount, l'index du tableau est hors limites, ce qui entraîne une erreur de segmentation.

Par exemple, si votre chaîne d'entrée est quelque chose comme ceci - "Hi. How are you doing?", alors elle a 4 ' ' caractères avant que \n soit atteinte, et la valeur de argCount augmentera jusqu'à { {X4}}.

1
Madhav Datt 3 janv. 2016 à 19:25

Ce que vous voulez faire est quelque chose comme ceci:

char** parse_cmdline( const char *cmdline )
{

Allouez votre tableau de pointeurs d'argument avec une longueur pour 1 pointeur et lancez-le avec 0.

char** arguments = malloc( sizeof(char*) );
arguments[0] = NULL;

Placez un pointeur char* sur le premier char de votre ligne de commande et rappelez-vous le début du premier argument

int argCount = 0, len = 0;
const char *argStart = cmdline;
const char *actPos = argStart;

Continuez jusqu'à la fin de la ligne de commande. Si vous trouvez un espace vide, vous avez un nouvel argument composé des caractères entre argStart et actPos. Allouez et copiez l'argument de la ligne de commande.

while( *actPos != '\n' && *actPos != '\0' )
{
    if( cmdline[lineCount] == ' ' && actPos > argStart )
    {
        argCount++; // increment number of arguments
        arguments = realloc( arguments, (argCount+1) * sizeof(char*) ); // allocate argCount + 1 (NULL at end of list of arguments)
        arguments[argCount] = NULL; // list of arguments ends with NULL
        len = actPos - argStart;
        arguments[argCount-1] = malloc( len+1 ); // allocate number of characters + '\0'
        memcpy( arguments[argCount-1], actPos, len ); // copy characters of argument
        arguments[argCount-1] = 0; // set '\0' at end of argument string
        argStart = actPos + 1; // next argument starts after blank
    }
    actPos++;
}
return arguments;  

}
1
Rabbid76 3 janv. 2016 à 19:48

Quelques suggestions que je donnerais est, avant d'appeler malloc, vous voudrez peut-être d'abord compter le nombre de mots que vous avez. puis appelez malloc comme char ** charArray = malloc(arguments*sizeof(char*));. Ce sera l'espace pour le char ** charArray. Ensuite, chaque élément de charArray doit être malléable par la taille du mot que vous essayez de stocker dans cet élément. Ensuite, vous pouvez stocker ce mot dans cet index. Ex. *charArray = malloc(sizeof(word)); Ensuite, vous pouvez le stocker sous le nom **charArray = word;

Soyez prudent avec l'arithmétique des pointeurs.

L'erreur de segmentation provient certainement du fait que vous essayez d'accéder à un élément d'un tableau dans un espace indéfini. Ce qui découle du fait que vous n'avez pas utilisé correctement l'espace pour le tableau.

0
3 janv. 2016 à 19:25