2010-03-02 4 views
2
main(){ 
    char *cmd1[20] = {NULL}; 
    int x = parse_command(cmd1); 
    printf("%s\ ",cmd1[0]); 
} 

parse_command(char *inTempString){ 
    char tempString[256]; 
    (call to function that assigns a string to tempString) 
    cmd1[0] = tempString; 
} 

Il y a un problème lors de l'impression du cmd1[0] dans les main. Je suis assez sûr que c'est une erreur de pointeur qui pend. Je ne sais pas vraiment comment y remédier.Problèmes avec des pointeurs et ballants tableaux de caractères en C

+2

Oui - je ne suis pas clair sur l'endroit où '' cmd1' dans parse_command' vient de. Ce code semble assez buggé dans des choses comme ça, ce qui obscurcit sans doute la vraie erreur. –

Répondre

0

Vous déclarez cmd1 dans main comme un caractère ** - c'est-à-dire un pointeur vers un pointeur sur char. Cependant, vous le passez ensuite à parse_command, que vous avez défini comme prenant un char *; un pointeur sur char.

Ceci compile uniquement en raison de la conversion automatique de pointeur vers n'importe quel pointeur vers char. C'est un artefact historique des anciennes versions de C qui utilisaient 'char *' à la place de 'void *'; dans votre cas, cela signifie simplement que le compilateur ignore l'erreur de type que vous avez faite plutôt que de vous le signaler.

+0

'cmd1' n'est pas déclaré' char ** '. C'est un tableau de pointeurs. Lorsqu'il est passé à une fonction, il se décompose en un pointeur vers le premier élément du tableau, qui est 'char **'. –

0

Oui, vous ne pouvez pas faire cela.

char tempString[256]; 

déclare une variable sur la pile dans la fonction parse_command, cette variable est hors de portée et les pointeurs cessent d'être valides lorsque parse_command retours.

Vous devez allouer la chaîne de commande sur le tas, de sorte qu'il reste valide lorsque parse_command renvoie. C'est un moyen.

parse_command(char *inTempString){ 
    char tempString[256]; 
    (call to function that assigns a string to tempString) 

    int cb = strlen(tempString)+1; 
    cmd1[0] = (char *)malloc(cb); 
    strcpy(cmd1[0], tempString); 
} 

Vous devez également appeler free(cmd[0]) avant les sorties principales.

En plus de cela, ce code ne compile pas. Vous ne pouvez pas référencer cmd1[0] à partir de la fonction parse_command. Vous devriez obtenir une incompatibilité de type lorsque vous essayez et passez cmd1 dans parse_command, Si vous voulez renvoyer un char * de parse_command alors il devrait être déclaré pour prendre un char ** comme argument, plus comme ceci.

parse_command(char **pcmd){ 
    char tempString[256]; 
    (call to function that assigns a string to tempString) 

    int cb = strlen(tempString)+1; 
    pcmd[0] = (char *)malloc(cb); 
    strcpy(pcmd[0], tempString); 
} 
+0

@Brooks: oui, en supposant que la plupart des 256 octets ne sont pas nécessaires la plupart du temps, nous allons de l'avant et lisons dans la pile, puis décidons de la quantité à allouer. –

0

Quelque chose comme cela fonctionnera:

parse_command(char **inTempString){ 
     static char tempString[256]; 
     strcpy(tempString,"some string you want to copy"); 
     inTempString[0] = tempString; 
} 
  • Dans votre code le tempString ne exister une fois que la fonction retourne. Vous devez le maintenir en vie même après l'affichage de la fonction . Vous pouvez allouer l'espace dynamiquement et désallouer plus tard ou vous pouvez le déclarer comme statique.
  • De même vous avez besoin de changer le type argument inTempString de char * à char **.
+1

Cela fonctionne, mais cela ne fonctionne que _once_. Je ne suis pas sûr que c'est une bonne recommandation à quelqu'un qui se bat avec des pointeurs. –

0

Vous essayez d'accéder à la variable cmd1 qui est à l'intérieur de la fonction mainparse_command.

Je dirais qu'au moins le cmd1[0] ressemblera à un nombre entier car il n'est pas déclaré avec cette méthode.

La cmd1 est déclarée comme array of char* mais le paramètre à la méthode est char* qui pourrait être un pointer to char array mais paspointer to array of char*. La meilleure façon de copier un tableau char dans un autre tableau char consiste à utiliser memcpy, strcpy ou des méthodes similaires acceptant les pointeurs sur src, dest et size à copier.

5

Votre programme présente deux problèmes.

D'abord, quand vous dites:

char *cmd1[20] = {NULL}; 

cmd1 est un tableau de 20 pointeurs vers char. Cela signifie que cmd1[i] pour i dans [0,20) est un pointeur sur char.

Il existe une règle dans C qui stipule que le passage d'un tableau à une fonction ne fait que passer le pointeur au premier élément du tableau à la fonction. À savoir, si vous aviez le code comme:

int ai[20]; 
f(ai); 

alors le type de ai dans l'appel de fonction est f(ai);int * et le pointeur est passé à f() est égal à &ai[0], le premier élément de ai.

Alors, quand vous faites:

parse_command(cmd1); 

vous savez immédiatement que la « chose » est passé à parse_command() est &cmd1[0], à savoir, un pointeur vers le premier élément de cmd1. Puisque cmd1[0] est de type char *, vous passez un char ** à parse_command. Par conséquent, votre déclaration:

parse_command(char *inTempString); 

est faux, vous devriez faire:

parse_command(char **inTempString); 

pour correspondre à votre appel. Cela suppose que parse_command() analysera plus d'une valeur dans cmd1. Si tel est le cas, vous devez également passer le nombre d'éléments dans cmd1 à parse_commnd() — car il ne peut pas savoir combien d'éléments cmd1 a. Votre deuxième problème est que vous ne pouvez pas renvoyer l'adresse d'une variable locale à partir d'une fonction dans C. Comme ci-dessus, en plus d'un appel de fonction, retourner un tableau dans C, ou affecter quelque chose à un tableau dans C rend également le nom d'un tableau "decay" à un pointeur vers son premier élément.

Donc, étant donné votre fonction:

/* changed inTempString to cmd1 because that's what you probably meant */ 
int parse_command(char *cmd1) 
{ 
    char tempString[256]; 
    /* call to function that assigns a string to tempString */ 
    cmd1[0] = tempString; 
    /* you need to return an int from here */ 
} 

le tempString dans l'affectation à cmd1[0] est en fait &tempString[0], à savoir, un pointeur vers le premier élément de tempString. Mais puisque tempString est détruit dès que la fonction retourne, le pointeur devient invalide. Vous ne pouvez pas utiliser la valeur plus tard.

En fait, en C, le nom d'un tableau se désintègre en un pointeur vers le premier élément dans tous les cas, à l'exception:

  • lorsqu'il est utilisé comme opérande pour sizeof opérateur, et
  • lorsqu'il est utilisé comme un opérande à pour être plus précis adresse de (&) opérateur

, dans des contextes d'objet, le nom d'un tableau ne se dégrade pas à un pointeur, et dans des contextes de valeur, il se désintègre à un pointeur . Voir this pour plus de détails.

Maintenant, comment devriez-vous résoudre votre deuxième problème? Cela dépend — vous pouvez soit allouer la mémoire dynamiquement dans parse_command(), et affecter cette mémoire à , ou vous pouvez faire tempStringstatic dans la fonction. Puisque static les variables d'une fonction ne sont pas détruites lorsqu'une fonction revient, vous pouvez continuer à utiliser un pointeur. L'allocation dynamique est plus de travail que vous devez vous soucier de l'échec de l'allocation et vous devez vous rappeler de libérer le pointeur lorsque vous avez terminé. static array est plus facile, mais vous devez faire attention car un autre appel à parse_command remplacera le tableau, le rendant moins générique.

En supposant que vous voulez aller de la « mémoire dynamique » route, voici un schéma que vous pouvez utiliser:

#include <stdio.h> /* printf */ 
#include <stdlib.h> /* malloc and free */ 

int main(void) /* main returns int */ 
{ 
    char *cmd1[20] = {NULL}; 
    /* number of commands. "sizeof cmd1" is the number of bytes 
     used by the cmd1 array, and "sizeof cmd1[0]" is the number 
     of bytes used by one element of the array. The division 
     gives you the number of elements. This is 20 of course 
     but doing it this way makes sure that changing "20" to any 
     number works. */ 
    size_t ncmds = sizeof cmd1/sizeof cmd1[0]; 
    /* pass the number of commands to "parse_command", since 
     it can't know otherwise */ 
    int x = parse_command(cmd1, ncmds); 
    int i; 
    for (i=0; i < x; ++i) { 
     printf("%s ", cmd1[i]); 
     free(cmd1[i]); 
    } 
    return 0; /* return a value from main */ 
} 

int parse_command(char **cmd1, size_t ncmds) 
{ 
    char *tempString; /* we will malloc this */ 
    int i; /* the number of mallocs done successfully */ 
    tempString = malloc(...); 
    if (tempString == NULL) { 
    /* failure, handle gracefully */ 
    } else { 
     ++i; /* make sure i doesn't exceed or equal ncmds */ 
    } 
    cmd1[0] = tempString; 
    /* do the above as many times as you need */ 
    return i; /* the number successfully assigned to */ 
} 
Questions connexes