Απλή απoρία στη C

Συζητήσεις για γλώσσες προγραμματισμού και θέματα σχετικά με προγραμματισμό.
Post Reply
User avatar
PASCAL
Wow! Terabyte level
Wow! Terabyte level
Posts: 3587
Joined: Wed Nov 23, 2005 10:58 pm
Academic status: Alumnus/a
Gender:

Απλή απoρία στη C

Post by PASCAL » Sat Feb 28, 2009 8:44 pm

Γιατί ο ακόλουθος κώδικας διαβάζει μόνο ένα char;

Code: Select all

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

int main() {
    char mychar;
        printf("Type a char: ");
        mychar = getchar();
        printf("Type a char: ");
        mychar = getchar();
		system("PAUSE");
	return EXIT_SUCCESS;
}
και αυτός δύο:

Code: Select all

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

int main() {
    char mychar;
        printf("Type a char: ");
        mychar = getchar();
        printf("Type a char: ");
        mychar = getchar();
        mychar = getchar();
		system("PAUSE");
	return EXIT_SUCCESS;
}
User avatar
cyberpython
Mbyte level
Mbyte level
Posts: 654
Joined: Wed Nov 21, 2007 8:18 pm
Academic status: Alumnus/a
Gender:
Location: Αθηνα
Contact:

Re: Απλή απoρία στη C

Post by cyberpython » Sat Feb 28, 2009 9:28 pm

Επειδή αφού διαβάσεις ένα χαρακτήρα με τη getchar() μένει(ουν) στο ρεύμα εισόδου ο χαρακτήρας(ες) αλλαγής γραμμής (σε win 2 - cr+lf).
Επίσης, τη system("PAUSE") καλό είναι να την αποφεύγεις αφού δεν είναι cross-platform (βάζε μια getchar() καλύτερα).
User avatar
netharis
Venus Former Team Member
Posts: 1845
Joined: Sun Jul 15, 2007 2:37 pm
Academic status: Alumnus/a
Gender:
Location: Seattle, Washington
Contact:

Re: Απλή απoρία στη C

Post by netharis » Sat Feb 28, 2009 10:08 pm

Δοκίμασε ανάμεσα απο τα input:

Code: Select all

fflush(stdin);
Image
Resistance is futile. Join the foss-side now!
"UNIX is very simple, it just needs a genius to understand its simplicity." - Dennis Ritchie
"The things that I want, by Max Payne. A smoke. A whiskey. For the sun to shine. I want to sleep, to forget. To change the past. Unlimited ammo and a license to kill. But right then, more than anything, I wanted her."
User avatar
PASCAL
Wow! Terabyte level
Wow! Terabyte level
Posts: 3587
Joined: Wed Nov 23, 2005 10:58 pm
Academic status: Alumnus/a
Gender:

Re: Απλή απoρία στη C

Post by PASCAL » Sun Mar 01, 2009 12:45 am

Eυχαριστώ παιδιά και ειδικά netharis, δούλεψε με τo flush του standard input.
User avatar
Theofaman
Mbyte level
Mbyte level
Posts: 984
Joined: Sat Sep 24, 2005 1:07 am
Academic status: Alumnus/a
Gender:
Location: Running from the weak side to the low post

Re: Απλή απoρία στη C

Post by Theofaman » Fri Jun 05, 2009 11:17 pm

Θα χρειαστώ την βοήθειά σας :-)
Ανοίγω ένα αρχείο της μορφής

Code: Select all

ab
cd
ef
και έπειτα το διαβάζω ανά γραμμή και την καταχωρώ σε ένα κόμβο της λίστας. Γιατί όταν τυπώνω την λίστα εμφανίζει μόνο την τελευταία εγγραφή του αρχείου? (δηλ. το ef). Αν εισάγω στην λίστα αριθμούς με μορφή μεταβλητών δουλεύει κανονικά. Κάτι συμβαίνει και το line δείχνει πάντα στο τέλος του αρχείου.

Code: Select all

char line[80];
fs = fopen ( "onomata.txt", "r") ;
 while(fgets(line, sizeof(line), fs) != NULL) 
{ 
           lnode = (item*)malloc(sizeof(item)); 
           printf("%s",line); 
           lnode = (struct dllist *)malloc(sizeof(struct dllist));
           node->val = line;
           append_node(lnode);
}    

for(lnode = head; lnode != NULL; lnode = lnode->next) {
    
     printf("%s\n", lnode->val);
     fprintf(ft, "%s\n", lnode->val);

Ευχαριστώ :)
Theo(pame na)fam(e mprizoles)an!
User avatar
HdkiLLeR
Venus Project Founder
Venus Project Founder
Posts: 4356
Joined: Tue Jan 27, 2004 4:41 pm
Academic status: Alumnus/a
Gender:
Location: New York, NY
Contact:

Re: Απλή απoρία στη C

Post by HdkiLLeR » Sat Jun 06, 2009 12:33 pm

Τα έχεις μπλέξει λίγο :) :)

το line είναι ένας buffer, τον οποίο κάθε φορά γεμίζεις με τα περιεχόμενα μιας γραμμής που διαβάζεις απο το file σου. Όταν κάνεις node->val = line; τότε ο pointer του node struct δείχνει στον buffer αυτόν. Συνεπώς αφού δεν έχεις ξεχωριστούς buffers / node και απλά παίζεις με τους pointers όλα τα node structs δείχνουν στην ίδια περιοχή (στον buffer των 80 bytes). Εάν στο τέλος του βάλεις εκεί το "ef" τότε όλα τα node->val θα είναι το "ef\0".

Γενικότερα τώρα:
  • το lnode το κάνεις init δύο φορές, την μία φορά σαν item και την άλλη σαν dllist -- memory leak (το πρώτο χάνεται και δεν γίνεται free)
  • το buffer σου δεν το κάνεις clear (zero) σε κάθε loop. Tο ότι βάζει \0 η fgets στο τέλος δεν λέει κάτι εάν διαβάζεις πχ σε ένα loop το "12345", στο buffer σου θα έχεις το 12345\0, εάν μετά διαβάσεις το 1 τότε το buffer σου θα έχει "1\0345\0" κοκ. Νομίζεις ότι είναι σωστό επειδή στο printf δεν κάνει print τπτ μετά το πρώτο \0 (string termination char)
  • η append_node() που είναι? :)
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d-->--- s+:+ a- C++(+++) BILS++++$ P--- L++++>+++++ E--- W+++ N+ o+ K w--
O M+ V-- PS++>+++ PE- Y++ PGP++ t+ 5+ X+ R* tv b++ DI- D+ G+++ e+++>++++ h r++ y++
------END GEEK CODE BLOCK------

"UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity." -- Dennis Ritchie
User avatar
Theofaman
Mbyte level
Mbyte level
Posts: 984
Joined: Sat Sep 24, 2005 1:07 am
Academic status: Alumnus/a
Gender:
Location: Running from the weak side to the low post

Re: Απλή απoρία στη C

Post by Theofaman » Sat Jun 06, 2009 1:59 pm

HdkiLLeR wrote:Τα έχεις μπλέξει λίγο :) :)

το line είναι ένας buffer, τον οποίο κάθε φορά γεμίζεις με τα περιεχόμενα μιας γραμμής που διαβάζεις απο το file σου. Όταν κάνεις node->val = line; τότε ο pointer του node struct δείχνει στον buffer αυτόν. Συνεπώς αφού δεν έχεις ξεχωριστούς buffers / node και απλά παίζεις με τους pointers όλα τα node structs δείχνουν στην ίδια περιοχή (στον buffer των 80 bytes). Εάν στο τέλος του βάλεις εκεί το "ef" τότε όλα τα node->val θα είναι το "ef\0".
Καταλαβαίνω ότι αυτό είναι το προβλημα αλλά δεν μπορώ να το λύσω :-( Δηλαδή προσπαθώ αντί να κάνω lnode->val = line να κάνω πχ lnode->val = *line για να παρω το περιεχόμενο και να μην δειχνει στο line το val.
Το line πως γινεται clear? Δεν βρηκα κατι στο google.
Ετσι τυπωνω την λίστα

Code: Select all

int printlist(struct dllist *lnode)
{
     
     for(lnode = head; lnode != NULL; lnode = lnode->next) {
    
     printf("%s\n", lnode->val);
     fprintf(ft, "%s\n", lnode->val);
    
      
   }   
   fclose (fs) ; 
   fclose (ft);
}
και αυτη είναι η append node

Code: Select all

void append_node(struct dllist *lnode) {
 if(head == NULL) {
  head = lnode;
  lnode->prev = NULL;
 } else {
  tail->next = lnode;
  lnode->prev = tail;
 }

 tail = lnode;
 lnode->next = NULL;
}
Theo(pame na)fam(e mprizoles)an!
User avatar
HdkiLLeR
Venus Project Founder
Venus Project Founder
Posts: 4356
Joined: Tue Jan 27, 2004 4:41 pm
Academic status: Alumnus/a
Gender:
Location: New York, NY
Contact:

Re: Απλή απoρία στη C

Post by HdkiLLeR » Sat Jun 06, 2009 5:30 pm

Theofaman wrote: Καταλαβαίνω ότι αυτό είναι το προβλημα αλλά δεν μπορώ να το λύσω :-( Δηλαδή προσπαθώ αντί να κάνω lnode->val = line να κάνω πχ lnode->val = *line για να παρω το περιεχόμενο και να μην δειχνει στο line το val.
Τα char arrays (και όλα τα arrays) δεν έχουν value (δηλαδή *p). Τι σημαίνει value ενός array (δεν έχει νόημα δηλαδή). Η απλούστατη λύση είναι copy. Αντί να κάνεις lnode->val = line θα πρέπει κάθε φορά να δεσμεύεις δηναμικά ένα άλλο κομμάτι heap space στο οποίο θα αποθηκεύεις τα περιεχόμενα του buffer. Εάν ήταν Java τι θα έκανες; Φαντάζομαι κάτι σε lnode.setVal(new String("...")), έ αυτό το new (που κάνει dynamic allocation για ένα new string object) θα πρέπει να το κάνεις είτε με malloc() (δηλαδή lnode->val = (char *)malloc(strlen(line)+1); strncpy(lnode->val, line, strlen(line));, είτε με strdup() (δηλαδή lnode->val = strdup(line);) To δεύτερο κάνει ότι το πρώτο απο μόνο του.
Theofaman wrote: Το line πως γινεται clear? Δεν βρηκα κατι στο google.
bzero(line, sizeof(line));
memset(line, 0, sizeof(line));


Στο τέλος ότι έχεις κάνει malloc()/calloc() φρόντισε να το κάνεις free(), ομοίως και ότι έχει προκύψει απο strdup() -- αλλιώς έχεις σοβαρά memory leaks/λάθη.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d-->--- s+:+ a- C++(+++) BILS++++$ P--- L++++>+++++ E--- W+++ N+ o+ K w--
O M+ V-- PS++>+++ PE- Y++ PGP++ t+ 5+ X+ R* tv b++ DI- D+ G+++ e+++>++++ h r++ y++
------END GEEK CODE BLOCK------

"UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity." -- Dennis Ritchie
User avatar
Theofaman
Mbyte level
Mbyte level
Posts: 984
Joined: Sat Sep 24, 2005 1:07 am
Academic status: Alumnus/a
Gender:
Location: Running from the weak side to the low post

Re: Απλή απoρία στη C

Post by Theofaman » Sat Jun 06, 2009 7:51 pm

Προσπάθησα να ορίσω μια νέα δομή που θα περιέχει μέσα εναν πίνακα char αλλά ο τρόπος που πρότεινες είναι καλύτερος και τρέχει.
Ευχαριστώ :) :)
Theo(pame na)fam(e mprizoles)an!
User avatar
PASCAL
Wow! Terabyte level
Wow! Terabyte level
Posts: 3587
Joined: Wed Nov 23, 2005 10:58 pm
Academic status: Alumnus/a
Gender:

Re: Απλή απoρία στη C

Post by PASCAL » Thu Oct 08, 2009 8:32 pm

Να ρωτήσω κάτι άλλο;
Όταν έχεις μια δομή:

Code: Select all

union example {
  char ch; 
  int xyz;
} str[10];
πώς μπορείς να γεμίσεις τον πίνακα str και το μέλος ch από κονσόλα; Γίνεται με scanf(), gets() κτλ ή κάπως αλλιώς;
Ευχαριστώ
User avatar
netharis
Venus Former Team Member
Posts: 1845
Joined: Sun Jul 15, 2007 2:37 pm
Academic status: Alumnus/a
Gender:
Location: Seattle, Washington
Contact:

Re: Απλή απoρία στη C

Post by netharis » Thu Oct 08, 2009 9:25 pm

Κανονικά μπορείς να διαβάσεις σε ένα union array. Eίναι και αυτό ένα κομμάτι μνήμης που έχει προσπελάσιμη διεύθυνση απο τις κανονικές μεθόδους εισόδου.
Δεδομένης της παραπάνω δήλωσης σου:

Code: Select all

#include <stdio.h>

union example 
{
  char ch;
  int xyz;
}str[10];

int main()
{
	/*Απλή ανάθεση */ /*str[0].ch = 'a';*/
	scanf("%c", &str[0].ch);
	printf("%c\n", str[0].ch);
	return 0;
}
Image
Resistance is futile. Join the foss-side now!
"UNIX is very simple, it just needs a genius to understand its simplicity." - Dennis Ritchie
"The things that I want, by Max Payne. A smoke. A whiskey. For the sun to shine. I want to sleep, to forget. To change the past. Unlimited ammo and a license to kill. But right then, more than anything, I wanted her."
User avatar
PASCAL
Wow! Terabyte level
Wow! Terabyte level
Posts: 3587
Joined: Wed Nov 23, 2005 10:58 pm
Academic status: Alumnus/a
Gender:

Re: Απλή απoρία στη C

Post by PASCAL » Thu Oct 08, 2009 11:07 pm

Α, ωραία. Βέβαια τώρα έχει σφάλμα εκτέλεσης :-p Just-In-Time Debugger 3860
User avatar
netharis
Venus Former Team Member
Posts: 1845
Joined: Sun Jul 15, 2007 2:37 pm
Academic status: Alumnus/a
Gender:
Location: Seattle, Washington
Contact:

Re: Απλή απoρία στη C

Post by netharis » Fri Oct 09, 2009 12:02 am

PASCAL wrote:Α, ωραία. Βέβαια τώρα έχει σφάλμα εκτέλεσης :-p Just-In-Time Debugger 3860
Μα C σε Visual Studio ? :-p

Άν ο κώδικας που γράφεις είναι πάνω σε μία κλητική ακολουθία, πόσταρε λίγο κώδικα αν μπορείς να του ρίξουμε μία ματιά.
Image
Resistance is futile. Join the foss-side now!
"UNIX is very simple, it just needs a genius to understand its simplicity." - Dennis Ritchie
"The things that I want, by Max Payne. A smoke. A whiskey. For the sun to shine. I want to sleep, to forget. To change the past. Unlimited ammo and a license to kill. But right then, more than anything, I wanted her."
User avatar
PASCAL
Wow! Terabyte level
Wow! Terabyte level
Posts: 3587
Joined: Wed Nov 23, 2005 10:58 pm
Academic status: Alumnus/a
Gender:

Re: Απλή απoρία στη C

Post by PASCAL » Fri Oct 09, 2009 1:31 am

Δεν πειράζει εντάξει το διόρθωσα! Thanks!
Και όντως, μακρία η C από Visual Studio :-p
Post Reply

Return to “Προγραμματισμός”