Λοιπόν, σου έγραψα καθαρό και σωστό τον κώδικα:
- Κώδικας: Επιλογή όλων
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX_INBUFFER (255+1)
#define WORDSIZE (20+1)
#define MAXWORDS 5
typedef struct {
char word[ WORDSIZE]; /* metabliti xaraktiron*/
char digits[ WORDSIZE ]; /* metabliti psifion*/
} infoT;
// char *new_string(char input_word[MAXWORDS],int number);
// -----------------------------------------------------------------------------------
char *read_line(char *line, int len)
{
if ( len == 0 )
return NULL;
if ( fgets(line, len, stdin) == NULL )
return NULL;
line[ strlen(line) - 1 ] = '\0';
return line;
}
// -----------------------------------------------------------------------------------
int main (void )
{
char inbuffer[ MAX_INBUFFER ] = "";
infoT *pairs = NULL;
int numwords = 0;
int i;
do {
printf("Enter number of words (1-%d): ", MAXWORDS);
read_line(inbuffer, MAX_INBUFFER);
numwords = atoi( inbuffer );
} while ( numwords < 1 || numwords > MAXWORDS );
pairs = calloc( numwords, sizeof(infoT) );
if ( !pairs ) {
printf("Memory allocation error\n");
return 1;
}
for (i=0; i < numwords; i++)
{
do {
printf("Enter word #%d: ", i+1);
read_line( inbuffer, MAX_INBUFFER );
strncpy( pairs[i].word, inbuffer, WORDSIZE-1 );
} while ( pairs[i].word[0] == '\0' );
}
puts("you entered:");
for (i=0; i < numwords; i++)
printf("\t\t%s\n", pairs[i].word);
free( pairs );
printf("END\n");
return 0;
}
Ελπίζω αυτή τη φορά να το διαβάσεις γιατί νομίζω πως την προηγούμενη φορά δεν τον διάβασες ή δεν του έδωσες την προσοχή που έπρεπε.
Σε ότι αφορά τη διαχείριση της δυναμικής μνήμης, πιστεύω πως πρέπει να είναι ξεκάθαρος. Όσο για τα υπόλοιπα που θα δεις, δεν είναι τίποτα άλλο από το ΠΕΤΑΜΑ ΣΤΑ ΣΚΟΥΠΙΔΙΑ συναρτήσεις όπως η scanf η sprintf και το format_str που χρησιμοποιούσες για να διαβάσεις το input από τον χρήστη.
Το κόλπο με το format_str δεν σε γλιτώνει από το γνωστό πρόβλημα του line-buffering και των απομειναριών, που έχουμε κατά κόρο αναλύσει στο φόρουμ. Ο πλέον συμβατός και αποτελεσματικός τρόπος να διαβάζεις την είσοδο από κονσόλα στη C είναι να διαβάζεις μονοκόμματη τη γραμμή εισόδου σε ένα δικό σου, πολύ μεγάλο string, και κατόπιν να κρατάς μόνο ότι χρειάζεσαι από τη γραμμή αυτή και να το βάζεις στισ μεταβλητές σου.
Στο παραπάνω κώδικα το string αυτό το ονομάζω
inbuffer με μέγιστο μήκος
MAX_INBUFFER και η ανάγνωσή του γίνεται με τη συνάρτηση:
read_line. Στον προηγούμενο κώδικα που σου είχα δώσει έκανα ακριβώς το ίδιο πράγμα, μόνο που εκεί τη συνάρτηση ανάγνωσης της γραμμής την ονόμαζα:
s_get (ή οποία λειτουργεί πολύ πιο γρήγορα από την τωρινή: read_line, γιατί η τωρινή χρησιμοποιεί την fgets, η οποία βάζει μέσα στο string και το ENTER που πατάει ο χρήστης... οπότε αναγκάζομαι να πηγαίνω και να το σβήνω μετά το διάβασμα).
Την 1η φορά που τη χρησιμοποιώ είναι όταν θέλω να διαβάσω το: numwords. Διαβάζω πρώτα τη γραμμή εισόδου: inbuffer με την read_line και κατόπιν μετατρέπω το inbuffer σε int με την συνάρτηση: atoi.
Τη 2η φορά που τη χρησιμοποιώ είναι όταν διαβάζω μέσα στο for-loop τα: pairs[i].word. Διαβάζω πρώτα τη γραμμή εισόδου μέσα στο inbuffer και κατόπιν αντιγράφω τους WORDSIZE-1 πρώτους χαρακτήρες της μέσα στο pairs[i].word.
Με αυτή την τεχνική, για να γίνει overflow η γραμμή εισόδου πρέπει ο χρήστης να πληκτρολογεί πάνω από 255 χαρακτήρες (MAX_INBUFFER-1) σε κάθε είσοδο. Πράγμα σπάνιο έως απίθανο, οπότε αποφεύγεται το πρόβλημα που παρουσιάζεται με τις scanf, getchar, κλπ