2010-12-02 3 views
2

édition Mise à jour:C - question malloc (peut-être quelque chose d'autre)

Alors, je suis en train d'obtenir ce code fonctionne sans utiliser scanf/fgets. Obtient des caractères de l'utilisateur, les place dans un tableau de pointeurs en utilisant une boucle while imbriquée dans une boucle for.

 
#define WORDLENGTH 15 
#define MAXLINE 1000 

int main() 
{ 
    char *line[MAXLINE]; 
    int i = 0; 
    int j; 
    int n; 
    char c; 


    for (n=0; c!=EOF; n){ 
     char *tmp = (char *) malloc(256); 
     while ((c=getchar())!=' '){ 
      tmp[i]=c;  // This is no longer updating for some reason. 
      i++; 
      } 
     line[n++]=tmp; // 
     i=0; 
     printf("\n%s\n",line[n]); //Seg fault here 
    } 

    for(j = 0; j (lessthan) n; j++){ 
     printf("\n%s\n", line[j]); 
     free (line[j]); 
    } 

    return 0; 

Donc, maintenant je reçois un défaut seg. Vous ne savez pas pourquoi tmp [i] ne se met pas correctement à jour. Travaille toujours dessus.

Je n'ai jamais autant appris sur la programmation pendant tout le semestre. S'il vous plaît continuez à m'aider à apprendre. J'adore ça.

Répondre

3

sizeof(WORLDLENGTH), pour un, est faux. malloc prend un entier et WORLDLENGTH est un nombre entier. sizeof (WORLDLENGTH) vous donnera la taille d'un entier, qui est de 4 si vous compilez pour un système 32 bits, donc vous allouez 4 octets.

Btw - while ((c=getchar())!=' '||c!=EOF) - Quelle est votre intention ici? Une condition comme (a!=b || a!=c) retournera toujours vrai si b! = C car il n'y a aucun moyen que b et c soient possibles. Et, comme d'autres l'ont souligné, vous imprimez line[i], où i est toujours 0. Vous vouliez probablement dire line[n]. Et vous ne terminez pas la chaîne tmp.

Et il n'y a pas de vérification de débordement, donc vous rencontrerez des bugs malveillants si un mot est plus long que WORDLENGTH.

+0

Ahhhh, je l'avais complètement oublié, mais je ne vais pas à nouveau! Toujours avoir le même problème si = – user527179

+1

yep besoin de faire malloc (sizeof (char) * WORDLENGTH); –

+0

sizeof (char) est garanti à 1 selon la norme. – EboMike

4

Vous imprimez line[i] et juste avant cela, vous définissez i à 0. Imprimez line[n] à la place.

De même, vous avez oublié le caractère de fin 0. Et votre code deviendra plus facile si vous faites tmp un tableau char, puis strdup avant d'attribuer à line[n].

+0

Fin du caractère 0? Tu veux dire \ 0? – user527179

+0

Depuis '\ 0' == 0, j'utilise normalement ce dernier :) –

1

Modifier votre ligne printf - vous devez imprimer line[n] plutôt que line[i].

1

d'abord votre formule malloc est erroné

malloc(sizeof(char)*WORDLENGTH); 

vous devez affecter le sizeof une fois char assez de la longueur de votre mot (également 15 semble un peu petite, votre sans compter le plus long mot dans le dictionnaire ou « iforgettoputspacesinmyphrasestoscrewtheprogrammer » cas lol ne soyez pas timide omble chevalier est petit que vous pouvez frapper 256 ou 512 ^^ facilement

également

printf("\n%s\n",line[i]); 

doit être changé en

int j = 0;

for(j=0;j<i;j++){ 
    printf("\n%s\n",line[j]); 
} 

votre i ne change jamais que vous puissiez imprimer toujours la même ligne

+0

Je n'étais pas sûr! J'ai peur d'allouer trop de mémoire potentiellement? Je vais m'assurer que je répare ça. – user527179

1

D'autres ont déjà dit certains problèmes spécifiques avec votre code, mais une chose qu'ils semblent avoir manqué est que c devrait être un int, non un char. Sinon, la comparaison avec EOF ne fonctionnera pas comme prévu.

En outre, le segfault que vous obtenez est à cause de cette séquence:

line[n++]=tmp; 
printf("\n%s\n",line[n]); 

Vous avez déjà incrémentée n à l'autre élément de tableau, alors vous essayez de l'imprimer. Cette deuxième ligne devrait être:

printf("\n%s\n",line[n-1]); 

Si vous voulez juste un code qui fonctionne (avec un libre « faire ce que vous voulez sacrément bien » licence), voici un extrait utile de ma bibliothèque de code.

Je ne suis pas sûr pourquoi vous pensez que fgets est à éviter, c'est en fait très pratique et très sûr. Je suppose que vous vouliez dire gets qui est moins pratique et totalement dangereux. Votre code est également sujet aux dépassements de tampon, car il écrira heureusement au-delà de la fin de votre zone allouée s'il reçoit beaucoup de caractères qui ne sont ni espace ni fin de fichier. Par tous les moyens, écrivez votre propre code si vous vous éduquez, mais une partie de cela devrait être l'examen du code pare-balles testé en production pour voir comment il peut être fait. Et, si vous êtes pas éduquer vous-même, vous vous faites un mauvais service en n'utilisant pas de code disponible gratuitement.

L'extrait suivant:

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

#define OK  0 
#define NO_INPUT 1 
#define TOO_LONG 2 
static int getLine (char *prmpt, char *buff, size_t sz) { 
    int ch, extra; 

    // Get line with buffer overrun protection. 
    if (prmpt != NULL) { 
     printf ("%s", prmpt); 
     fflush (stdout); 
    } 
    if (fgets (buff, sz, stdin) == NULL) 
     return NO_INPUT; 

    // If it was too long, there'll be no newline. In that case, we flush 
    // to end of line so that excess doesn't affect the next call. 
    if (buff[strlen(buff)-1] != '\n') { 
     extra = 0; 
     while (((ch = getchar()) != '\n') && (ch != EOF)) 
      extra = 1; 
     return (extra == 1) ? TOO_LONG : OK; 
    } 

    // Otherwise remove newline and give string back to caller. 
    buff[strlen(buff)-1] = '\0'; 
    return OK; 
} 

 

// Test program for getLine(). 

int main (void) { 
    int rc; 
    char buff[10]; 

    rc = getLine ("Enter string> ", buff, sizeof(buff)); 
    if (rc == NO_INPUT) { 
     printf ("No input\n"); 
     return 1; 
    } 

    if (rc == TOO_LONG) { 
     printf ("Input too long\n"); 
     return 1; 
    } 

    printf ("OK [%s]\n", buff); 

    return 0; 
} 

Il est une fonction d'entrée de ligne utile qui a la même protection contre le débordement de la mémoire tampon comme fgets et peut également détecter les lignes saisies par l'utilisateur qui sont trop longue. Il jette également le reste de la ligne trop longue pour ne pas affecter la prochaine opération d'entrée.

Sample fonctionne avec 'bonjour', CTRLD, et une chaîne qui est trop grand:

pax> ./qq 
Enter string> hello 
OK [hello] 

pax> ./qq 
Enter string> 
No input 

pax> ./qq 
Enter string> dfgdfgjdjgdfhggh 
Input too long 

pax> _ 

Pour ce que ça vaut la peine (et ne remettre pas en tant que votre propre travail puisque vous serez presque certainement pris pour du plagiat - n'importe quel éducateur à moitié décent cherchera votre code sur le net comme la première chose qu'il fait), c'est ainsi que je l'aborderais.

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

#define WORDLENGTH 15 
#define MAXWORDS 1000 

int main (void) { 
    char *line[MAXWORDS]; 
    int numwords = 0; // Use decent variable names. 
    int chr, i; 

    // Code to run until end of file. 

    for (chr = getchar(); chr != EOF;) {   // First char. 
     // This bit gets a word. 

     char *tmp = malloc(WORDLENGTH + 1);  // Allocate space for word/NUL 
     i = 0; 
     while ((chr != ' ') && (chr != EOF)) {  // Read until space/EOF 
      if (i < WORDLENGTH) {     // If space left in word, 
       tmp[i++] = chr;     // add it 
       tmp[i] = '\0';      // and null-terminate. 
      } 
      chr = getchar();      // Get next character. 
     } 
     line[numwords++] = tmp;     // Store. 

     // This bit skips space at end of word. 

     while ((chr == ' ') && (chr != EOF)) { 
      chr = getchar(); 
     } 
    } 

    // Now we have all our words, print them. 

    for (i = 0; i < numwords; i++){ 
     printf ("%s\n", line[i]); 
     free (line[i]); 
    } 

    return 0; 
} 

Je vous suggère de lire cela et Studdy les commentaires afin que vous sachiez comment il fonctionne. N'hésitez pas à poser des questions dans la section des commentaires et je vais répondre ou clarifier.


Voici un échantillon analysé:

pax$ echo 'hello my name is pax andthisisaverylongword here' | ./testprog 
hello 
my 
name 
is 
pax 
andthisisaveryl 
here 
+0

Je ne veux pas utiliser les fgets dans une tâche où nous ne sommes pas supposés l'avoir utilisé parce que les enseignants, pour une raison quelconque, n'aiment pas quand vous recevez de l'aide et que les gens vous offrent des réponses plus utiles que ce qu'ils sont. vous enseigne actuellement. Pourquoi ils font cela, je n'en ai aucune idée. J'apprécie vraiment cet exemple! Tellement mieux que celui que j'ai, pourtant, je dois forcer à travers ce scénario. Je suppose que c'est une bonne pratique de programmation d'être coincé dans une boîte aussi = \ – user527179

+1

Ensuite, je vais offrir un conseil précieux. _Know_ combien de mémoire vous avez allouée et _know_ combien vous avez déjà écrit. Jamais laisser ce dernier dépasser le précédent :-) En tout cas, j'applaudirais un étudiant en train de faire ses propres recherches. Regardez dans 'fgets' et comprenez-le. Si vous y êtes invité, vous pourrez défendre votre choix dans ce cas. Si un éducateur me marquait pour savoir plus qu'eux, j'en parlerais à l'établissement d'enseignement. YMMV. – paxdiablo

+0

Peut-être que c'est la raison pour laquelle je reçois une erreur de segmentation en ce moment? = \ C'était si proche de travailler et ensuite je change le code: faute Seg. Changer le retour? Seg faute. Whyyyyyyyyyyy – user527179