Προς το περιεχόμενο

Που είναι το λάθος; [C]


xpapias

Προτεινόμενες αναρτήσεις

Δημοσ.

Έχω ένα αρχείο με ονόματα. Θέτω ένα array από strings και προσπαθώ σε καθένα από τα strings του να δίνω μια τιμή από αυτές που διαβάζω από το αρχείο. Δηλ. γράφω στη main:

 

char *a[100];

int i=0;

FILE *fl = fopen ("arxeio","r");

while (fscanf(fl,"%s ",a) !=EOF)

i++;

fclose (fl);

 

Το πρόγραμμα γίνεται compile χωρίς σφάλματα, όμως όταν το τρέχω προκύπτει μήνυμα λάθους. Όταν αντί για a στην fscanf ΄βαλω ένα άλλο string (που το έχω δηλώσει πχ ως char t[20]) το πρόγραμμα δουλεύει κανονικά.

 

Τι κάνω λάθος;

Δημοσ.

Διότι το char *a[100] δηλώνει ένα πίνακα 100 δεικτών σε χαρακτήρα ενώ το char t[20] δηλώνει ένα πίνακα 20 χαρακτήρων.

Αποφάσισε: 1η διάσταση Πόσα string έχεις και 2η διάσταση Πόσους χαρακτήρες θα βάζεις. Μετά... μετά εδώ είμαστε...

Δημοσ.
Διότι το char *a[100] δηλώνει ένα πίνακα 100 δεικτών σε χαρακτήρα ενώ το char t[20] δηλώνει ένα πίνακα 20 χαρακτήρων.

Αποφάσισε: 1η διάσταση Πόσα string έχεις και 2η διάσταση Πόσους χαρακτήρες θα βάζεις. Μετά... μετά εδώ είμαστε...

 

Μισό.. Θέλω να αποθηκεύω ονόματα. Άν δηλώσω char *a[100] και μετά a[1]="Peter", a[2]="George" κλπ, μου δουλεύει κανονικά. Για ποιό λόγο δε μπορώ να βάλω το a στο fscanf;

 

Δηλ. άν πω ότι θέλω να έχω ένα πίνακα 20 strings με 50 χαρακτήρες το καθένα, πως το δηλώνω;

Δημοσ.

Αν ως ανώτατο όριο για το κάθε string που θα διαβάζεται θεωρείς έστω x χαρακτήρες, ο πίνακας a αρκεί να δηλωθεί ώς:

>char a[100][x+1];

 

Αν τώρα θες να το κάνεις πιο τυπικά, θα πρέπει ο a να είναι πίνακας δεικτών σε πίνακα χαρακτήρων, να έχεις έναν αρκούντως μεγάλο buffer όπου θα αποθηκεύεις προσωρινά το κάθε string για να μετρήσεις το μήκος του, και μετά να δεσμεύεις δυναμικά την απαιτούμενη μνήμη για να τοποθετήσεις το κάθε string...

 

***Edit: Ουπς, sorry παιδιά που μπήκε σαν σφήνα, βλέπω είχατε ξεκινήσει να το συζητάτε!

Δημοσ.

Η πρόταση a[1]="Peter"; αν έχει προηγηθεί η δήλωση char *a[100]; είναι σωστή διότι στην ήδη κατειλημένη μνήμη "Peter" δείχνει ο δείκτης a[1]. Αν γράψω scanf("%s",a[1]); που να βάλει η κακομοίρα η scanf τα data; Θα πρέπει να έχει γίνει είτε κάτι σαν αυτό char a[20][50] ή κάτι με malloc -είναι νωρίς ακόμα-.

 

Ποιό βιβλίο διαβάζεις; Έχεις το http://cm.bell-labs.com/cm/cs/cbook/ ;

 

No problem parsifal.

Άλλωστε για μένα είναι ώρα για ύπνο...

Δημοσ.

Αν και δεν χρησιμοποιώ την fscanf για τέτοιου είδους δουλείες (τώρα μάλλον θα αλλάξω γνώμη ;) ) στην παρούσα περίπτωση σχεδίασα τον παρακάτω κώδικα ο οποίος διαβάζει 100 ονόματα ή μέχρι το EOF από ένα αρχείο κειμένου με την προϋπόθεση πως κάθε όνομα έχει μήκος ως 12 χαρακτήρες σε διαφορετική περίπτωση το πρόγραμμα σταματά -μεταξύ μας δύσκολα θα βρεις όνομα (όχι επώνυμο) στην Ελλάδα τόσο μεγάλο :).

Κάθε όνομα αποθηκεύεται σε έναν buffer των 14 ωφέλιμων χαρακτήρων ο οποίος αργότερα μικραίνει στο πραγματικό μέγεθος του ονόματος για εξοικονόμηση μνήμης (ομολογώ πως μου άρεσε η ιδέα του Parsifal).

 

Ο κώδικας έχει γραφθεί σε CodeGear Turbo C++ Express και έχει δοκιμασθεί με input stream των 23 ονομάτων - φυσικά μπορεί να περιέχει Bugs.

 

>
//---------------------------------------------------------------------------

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

//---------------------------------------------------------------------------
#define	MAX_NAME_LIST	100

FILE	*Stream = NULL;
int		nArrayIdx;
char	*pszArray[MAX_NAME_LIST];

int main(int argc, char* argv[])
{
if((Stream=fopen(argv[1],"r"))!=NULL)
 {
	memset(pszArray,0,sizeof(char)*MAX_NAME_LIST);

	for(nArrayIdx=0;nArrayIdx<MAX_NAME_LIST;nArrayIdx++)
	 {
		if((pszArray[nArrayIdx]=malloc(15))==NULL)
		 {
			printf(" Out of memory!\n");
			break;
		 }
		memset(pszArray[nArrayIdx],0,sizeof(unsigned char)*15);

		if(fscanf(Stream,"%14s",pszArray[nArrayIdx])==EOF)
		 break;

		if(strlen(pszArray[nArrayIdx])>=13)
		 {
			printf(" Name on line or delimeter #%d very long - %.12s ..!\n",
					nArrayIdx,pszArray[nArrayIdx]);
			break;
		 }

		printf(" %d\n",strlen(pszArray[nArrayIdx]));
		if((pszArray[nArrayIdx]=realloc(pszArray[nArrayIdx],
										(size_t)strlen(pszArray[nArrayIdx])+1))==NULL)
		 {
			printf(" Memory reallocation failure!\n");
			break;
		 }

		printf(" pszArray[%.2d] = %s (Actual Length:%d)\n",
				nArrayIdx,pszArray[nArrayIdx],strlen(pszArray[nArrayIdx]));
	 }

	fclose(Stream);

	for(nArrayIdx=0;nArrayIdx<MAX_NAME_LIST;nArrayIdx++)
	 if(!pszArray[nArrayIdx])
	  break;
	 else
	  free(pszArray[nArrayIdx]);
 }
else
 printf(" Cannot open file for read - %s\n",argv[1]);

printf(" HIT ANY KEY TO QUIT ...");
getch();
return 0;
}
//---------------------------------------------------------------------------

 

Υ.Γ.

Άραγε μπορεί να σχεδιασθεί αποδοτικός κώδικας ώστε να αίρεται ο φυσικός περιορισμός στο μέγεθος του ονόματος με την χρήση της fscanf (να μην θέτουμε περιορισμό στο μέγεθος της ονομασίας).

Δημοσ.

Σας ευχαριστώ και τους 3 για τις απαντήσεις, και ειδικά τον directX που έκατσε και έφτιαξε και κώδικα. Βιβλίο έχω ήδη των Kernighan και Richie. Θα κοιτάξω τον κώδικα του directX και θα διαβάσω και από το βιβλίο. Απ'οτι κατάλαβα χωρίς memory allocation δεν γίνονται και πολλά γενικά...

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...