2017-09-10 2 views
1

mon code fonctionnerait ainsi:chaîne d'entrée C-fracture - erreur de segmentation

input : a[]="create /dir/bar" 

et enregistrer dans cette chaîne:

b[]=create 
c[]=/dir/bar 

il y a aussi un cas dans lequel enregistrer une sauvegarde autre chaîne: (par exemple)

a[]=write /foo/bar "test" 

b[]= write 
c[]=/foo/bar 
d[]=test (without the "") 

mon code est le suivant:

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#define SPACE ' ' 

void divide(char a[], char b[], char c[], char d[]); 

int main(int argc, char const *argv[]) { 
    char a[50+1]; 
    char b[50+1]; 
    char c[50+1]; 
    char d[50+1]; 
    int i; 

    scanf("%s\n", a); 

    divide(a, b, c, d); 

    for(i=0; b[i]!='\0'; i++) 
     printf("%s %s %s \n", b, c, d); 

    return 0; 
} 



void divide(char a[], char b[], char c[], char d[]){ 
    int i, j; 

    for(i=0; a[i]!=SPACE; i++) 
     b[i]=a[i]; 

    b[i]='\0'; 

    for(; a[i]==SPACE; i++) 
     ; 

    for(j=0; a[i]!='\0'; i++, j++) 
     c[j]=a[i]; 

    c[j]='\0'; 
    for(; a[i]==SPACE; i++) 
     ; 

    if(a[i]=='"'){ 
     i++; 
     for(j=0; a[i]!='"'; i++) 
      d[j]=a[i]; 

     d[j]='\0'; 

     return; 
    } 
} 

mais cela ne fonctionne pas pour une erreur de segmentation après l'entrée du programme. où est le problème?

Je ne dois pas utiliser malloc, car il passe trop de temps à travailler (je dois obtenir des milliers de ces lignes) et ne respecte pas une limite. (Je travaille pour un projet dans mon université)

+0

1) 'scanf ("% s \ n ", a);' -> 'scanf ("% 50 [^ \ n] ", a);' – BLUEPIXY

+0

'pour (i = 0; b [i]! = '\ 0'; je ++) '?? – BLUEPIXY

+0

2) 'pour (j = 0; a [i]! = '\ 0'; i ++, j ++)' -> 'pour (j = 0; a [i]! = ESPACE; i ++, j ++)' – BLUEPIXY

Répondre

0

Vous pouvez être faire cela un peu plus difficile qu'il doit être. Oui, vous pouvez marquer une chaîne par des appels répétés à sscanf ou avec des lectures répétées avec scanf, mais la bibliothèque C fournit un outil pour marquer les mots d'une ligne de texte. Assez bien nommé strtok.

Vous déclarez simplement une chaîne constante contenant les délimiteurs sur lesquels vous souhaitez interrompre les mots (par exemple delims = " \t"; pour casser les mots sur l'espace ou la tabulation, puis appelez strtok (str, delims) pour retourner le premier jeton (mot), puis bouclez appelle strtok (NULL, delims) pour analyser les mots restants (ou jusqu'à ce que vous atteigniez votre maximum de 3 mots).

(note le premier appel à strtok utilise str comme premier paramètre, alors que tous les appels utilisent NULL)

Ceci est une manière beaucoup plus souple pour gérer un nombre inconnu de jetons dans une chaîne.

Au lieu d'utiliser a[], b[], c[], etc .. envisager d'utiliser un seul buf[] à lire la ligne d'entrée dans, puis un tableau de chaînes pour maintenir les paramètres (qui vous permet d'utiliser un indice variable au cours de vos boucles sur strtok pour affecter et copier la chaîne correcte à l'index associé). N'utilisez pas void comme retour dans des circonstances comme celle-ci.

Pourquoi ne pas utiliser un retour significatif (comme le nombre de paramètres dans la ligne de texte). De cette façon, vous savez combien ont été lus (ou tokenisés) dans votre fonction de division. Donnez-lui un retour qui peut fournir des informations utiles, par ex.

size_t divide (char *buf, char (*params)[MAXC+1]); 

qui retourne maintenant un type size_t contenant le nombre de paramètres qui résultent de chaque appel à diviser.

Mettre complètement (et en utilisant fgets pour lire toute la ligne d'entrée), vous pouvez faire quelque chose comme ce qui suit:

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

enum { MAXP = 3, MAXC = 50 }; /* max parameters & chars */ 

size_t divide (char *buf, char (*params)[MAXC+1]); 

int main (void) { 

    char buf[MAXC * 4 + 1] = ""; 
    char params[MAXP][MAXC + 1]; /* array to hold 3 parameters */ 
    size_t i, len, nparams = 0; 

    /* use fgets for line-oriented user input */ 
    printf ("\nenter commands: "); 
    if (!fgets (buf, sizeof buf, stdin)) { 
     fprintf (stderr, "error: insufficient input.\n"); 
     return 1; 
    } 

    len = strlen (buf);   /* get length */ 
    if (buf[len - 1] == '\n') /* validate last char is '\n' */ 
     buf[--len] = 0;   /* overwrite with nul-terminating char */ 
    else {      /* short read -- handle error */ 
     fprintf (stderr, "error: incomplete input read.\n"); 
     return 1; 
    } 

    nparams = divide (buf, params); 

    for (i = 0; i < nparams; i++) 
     printf ("parameter[%zu] : %s\n", i, params[i]); 

    return 0; 
} 

/* divide using strtok */ 
size_t divide (char *buf, char (*params)[MAXC+1]) 
{ 
    char *delims = " \t", /* delimiters for strtok */ 
     *p = buf;   /* pointer to buf */ 
    size_t n = 0;   /* var to return number of params */ 

    p = strtok (buf, delims);   /* tokenize fist paramter */ 

    while (p) { /* now loop until all words exhausted or limit reached */ 
     strncpy (params[n++], p, MAXC); /* copy token to params array */ 
     if (n == MAXP)     /* check if limit reached */ 
      break; 
     p = strtok (NULL, delims);  /* get next token */ 
    } 

    return n; /* return the number of parameters found */ 
} 

Exemple d'utilisation/sortie

$ /bin/splitparams 

enter commands: create /dir/bar 
parameter[0] : create 
parameter[1] : /dir/bar 

$ ./bin/splitparams 

enter commands: write /foo/bar "test" 
parameter[0] : write 
parameter[1] : /foo/bar 
parameter[2] : "test" 

Ou fournir un tas de mots supplémentaires (pour valider le traitement de seulement 3)

$ ./bin/splitparams 

enter commands: write /foo/bar "test" and some more stuff 
parameter[0] : write 
parameter[1] : /foo/bar 
parameter[2] : "test" 
0

Si vous exécutez ce programme simple

#include<stdio.h> 

int main(int argc, char const *argv[]) { 
    char a[50+1]; 

    scanf("%s\n", a); 
    printf("|%s|\n", a); 

    return 0; 
} 

et donnez l'entrée « créer foo », vous obtiendrez la sortie

| créer |

Comme vous pouvez le voir seulement obtenu le premier mot, à savoir « créer », au lieu de l'attendre « créer foo » comme

scanf("%s\n", a); 

ne donnera le premier mot. Par conséquent, votre fonction divide échouera. Au lieu de scanf que vous pourriez faire

fgets(a, 51, stdin); 

pour vous assurer que l'entrée soit lue dans un tableau a.

En général, votre programme manque de beaucoup de vérification de gamme et de validation d'entrée. Vous devriez ajouter ça.

Un autre problème que je vois est que dans le cas où l'entrée est

create /dir/bar 

vous n'initialiser la chaîne d mais vous imprimez encore dans le principal. C'est un comportement indéfini.

Essayez:

char d[50+1]; 
d[0] = '\0'; // Add this line 
+0

ok merci! Je répare et ça marche ... merci pour votre soutien! –