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

ΕΚΣΦΑΛΜΑΤΩΣΗ ΠΡΟΓΡΑΜΜΑΤΟΣ ΣΕ C


nek1313

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

Δημοσ. (επεξεργασμένο)

γεια σας , σημερα εγραφα στη σχολη μια προοδο και στο πρωτο θεμα ζητουσε να γραψουμε ενα προγραμμα σε C που  να εκτυπωνει στο τερματικο το 

μεγαλυτερο σε μηκος ορισμα της main()  αλλα να το εμφανιζει  με μετατροπη των μικρων γραμματων του σε κεφαλαια .

Αν υπαρχουν περισσοτερα απο ενα ορισματα με το ιδιο μεγιστο μηκος , να εκτυπωνει το πρωτο .

Εγω εκανα αυτο :

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

int main(int argc , char *argv[])
{
	
	int i ;
	int y = 0 ;
	char s[y] ;
	int j = 0 ;
	

	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > y)
		{
			y = i ;
		}
	}
	
    strcpy(s,argv[y]);
	while (s[j])
	{
		s[j] = toupper(s[j]);
		j ++;

	}
	printf("%s \n" , s) ;
	return (0);
}

το οποιο περναει απο τον compiler , δεν βγαζει λαθη κατα την εκτελεση αν τα ορισματα εχουν ενα κανονικο μηκος (κατω απο 20 χαρακτηρες),

ομως βγαζει σε αρκετες περιπτωσεις λαθος αποτελεσμα  . 

Πιστευω οτι εχω κανει καποιο λογικο λαθος στο κωδικα , το οποιο δεν μπορω να ανιχνευσω μεχρι τώρα.

Ολες οι ιδεες σας ειναι φυσικα ευπροσδεκτες  .

 Για να βγαλει σωστο αποτελεσμα , εχω παρατηρησει οτι τα μηκη των ορισματων πρεπει να ακολουθουν ενα μοτιβο οπως τα διαβαζεις απο το πρωτο προς το τελευταιο .

Επεξ/σία από nek1313
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το πρόβλημα είναι όταν γράφεις char s[y];

Δεν κάνει αυτό που θέλεις. Η πιο εύκολη λύση που μπορείς να κάνεις είναι να καλείς toupper(argv[y]) για όλο το μέγεθος του argv[y] όπου το argv[y] το μεγαλύτερο ορισμα. 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

δε νομιζω να φταιει αυτο που λες , γιατι και αυτος ο κωδικας (χωρις το char s[y] ) που εκτυπωνει απλα το μεγαλυτερο σε μηκος ορισμα φαινεται να εχει προβλημα ,

γιατι δε τρεχει σωστά .

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

int main(int argc , char *argv[])
{
	
	int i ;
	int y = 0 ;
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > y)
		{
			y = i ;
		}
	}
	printf("%s \n" , argv[y]) ;
	return 0;
}

  

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)
16 λεπτά πριν, nek1313 είπε

δε νομιζω να φταιει αυτο που λες , γιατι και αυτος ο κωδικας (χωρις το char s[y] ) που εκτυπωνει απλα το μεγαλυτερο σε μηκος ορισμα φαινεται να εχει προβλημα ,

γιατι δε τρεχει σωστά .


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

int main(int argc , char *argv[])
{
	
	int i ;
	int y = 0 ;
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > y)
		{
			y = i ;
		}
	}
	printf("%s \n" , argv[y]) ;
	return 0;
}

Πριν ήμουν από κινητό και το είδα γρήγορα αλλά αυτό που σου είπα ήταν λάθος έτσι και αλλιώς.

Το λάθος σου είναι ότι συγκρίνεις το strlen(..) με το y αλλά το y δεν είναι το μεγαλύτερο μήκος αλλά ένα index. Το ότι σου δούλευε πριν είναι επειδή έτυχε. Θες μια μεταβλητή για το index του μεγαλύτερο σε μήκος arg αλλά και μια για το μέγιστο μήκος. Αν εξαρχής είχες βάλει καλύτερα ονόματα μεταβλητών αντί για y θα το είχες δει μόνος σου.

Επεξ/σία από kaliakman
  • Thanks 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

σε ευχαριστω , την εβγαλα . 

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

int main(int argc , char *argv[])
{
	
	int i ;
	int pos_max = 0 ;
	int max = 0 ; 
	char s[max];
	int c = 0 ; 
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > max)
		{
			max = strlen(argv[i]);
			pos_max = i ;
		}
	}
	strcpy(s,argv[pos_max]);
	while (s[c])
	{
		s[c] = toupper(s[c]);
		c ++;
	}
	printf("%s \n" , s) ;
	return 0;
}

εχεις απολυτο δικαιο σε αυτο με τα ονοματα των μεταβλητων ,στην αρχη το ειχα σκεφτει αλλα μετα  το ξεχασα τελειως και χαθηκα στις ετοιμες  strlen , strcpy, toupper

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

3 λεπτά πριν, nek1313 είπε

σε ευχαριστω , την εβγαλα . 


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

int main(int argc , char *argv[])
{
	
	int i ;
	int pos_max = 0 ;
	int max = 0 ; 
	char s[max];
	int c = 0 ; 
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > max)
		{
			max = strlen(argv[i]);
			pos_max = i ;
		}
	}
	strcpy(s,argv[pos_max]);
	while (s[c])
	{
		s[c] = toupper(s[c]);
		c ++;
	}
	printf("%s \n" , s) ;
	return 0;
}

εχεις απολυτο δικαιο σε αυτο με τα ονοματα των μεταβλητων ,στην αρχη το ειχα σκεφτει αλλα μετα  το ξεχασα τελειως και χαθηκα στις ετοιμες  strlen , strcpy, toupper

Διόρθωσες το πρόβλημα αλλά το πρώτο που σου είπα το άφησες. Το char s[max] που γράφεις δεν ισχύει. Γράφεις ότι θέλεις ένα array με 0 χαρακτήρες. Πάλι κατά τύχη δουλεύει. Είτε δεν θα αντιγραψεις το string σε άλλη μεταβλητή είτε θα πρέπει να κάνεις πρώτα δυναμική δέσμευση μνήμης και μετά αντιγραφή. 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

int main(int argc , char *argv[])
{
	
	int i ;
	int pos_max = 0 ;
	int max = 0 ; 
	int c = 0 ; 
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > max)
		{
			max = strlen(argv[i]);
			pos_max = i ;
		}
	}
	while (argv[pos_max][c])
	{
		argv[pos_max][c] = toupper(argv[pos_max][c]);
		c ++;
	}
	printf("%s \n" , argv[pos_max]) ;
	return 0;
}

μαλλον αυτο προτεινεις , τη malloc καλυτερα να την αποφυγω σε αυτο αφου δεν ειναι αναγκαια .

παντως η εξεταση ηταν τρεχει (10)/ δε τρεχει(0) , οποτε αν εγραφα το παραπανω με strcpy  (βγαζει οσες φορες δοκιμασα σωστο αποτελεσμα) 10 θα μου εβαζε !

για καποιο  λογο η C το  καταλαβαινει το  char s[max] και το αρχικοποιει με max = τη τιμη που βγηκε απο το loop πριν το χρησιμοποιησει ... 

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)
33 λεπτά πριν, nek1313 είπε

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

int main(int argc , char *argv[])
{
	
	int i ;
	int pos_max = 0 ;
	int max = 0 ; 
	int c = 0 ; 
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > max)
		{
			max = strlen(argv[i]);
			pos_max = i ;
		}
	}
	while (argv[pos_max][c])
	{
		argv[pos_max][c] = toupper(argv[pos_max][c]);
		c ++;
	}
	printf("%s \n" , argv[pos_max]) ;
	return 0;
}

μαλλον αυτο προτεινεις , τη malloc καλυτερα να την αποφυγω σε αυτο αφου δεν ειναι αναγκαια .

παντως η εξεταση ηταν τρεχει (10)/ δε τρεχει(0) , οποτε αν εγραφα το παραπανω με strcpy  (βγαζει οσες φορες δοκιμασα σωστο αποτελεσμα) 10 θα μου εβαζε !

για καποιο  λογο η C το  καταλαβαινει το  char s[max] και το αρχικοποιει με max = τη τιμη που βγηκε απο το loop πριν το χρησιμοποιησει ... 

Ναι αυτή είναι σωστή λύση. 

Τώρα, αυτό που λες δεν παίζει σαν σενάριο. Είσαι απλά τυχερός και δεν σκάει. Αν το δοκιμάσεις σε άλλο μηχάνημα ή αύριο μπορεί να σκάει συνέχεια. 

Αν σε πέρναγε δεν θα είχε κοιτάξει τι κάνεις. Εγώ πάντως αν το νόημα της προόδου είναι αν ξέρετε c πιθανότατα δεν θα σε πέρναγα. 

Γνώμη μου πάντα, μην παρεξηγηθω. 

Επεξ/σία από kaliakman
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Η λογική των καθηγητών, μιας και το ανέφερες,  είναι "αν τρέχει,  την κοιτάω παρακάτω να δω τι κάνει. Αν δεν τρέχει ,  δεν την κοιτάω καν" και όχι αυτό που λες, δηλαδή τρέχει =10.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

@kaliakman

Πιστευω οτι δε σκαει σε κανενα μηχανημα το συγκεκριμενο , και το ξερω οτι  δεν ειμαι και  καλος στη C . 

@Lanike71

o συγκεκριμενος καθηγητης μας το ειχε δηλωσει ξεκαθαρα και το εγραφε και πανω στα θεματα  ,

στο πρωτο θεμα που επιανε 5/10 δε κοιταει καθολου το κωδικα ,

τρεχει αυτοματα μαλλον με ενα σκριπτακι τα 200+ πρωτα θεματα ολων των φοιτητων

και οσα βγαζουν το σωστο αποτελεσμα παιρνουν 10 ,

οσα κατι αλλο η και τιποτα παιρνουν 0 . Δε τον ενδιαφερει το ποσο αποδοτικος ,

καλογραμμενος η με καλα σχολια ειναι ο κωδικας , τον ενδιαφερει μονο αν κανει 

αυτο που ζητηθηκε . Στο δευτερο θεμα κοιταει αναλυτικα το κωδικα και δινει καποιες μοναδες ασχετα με τον αν η πως τρεχει .

 

Επεξ/σία από nek1313
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

12 ώρες πριν, nek1313 είπε

για καποιο  λογο η C το  καταλαβαινει το  char s[max] και το αρχικοποιει με max = τη τιμη που βγηκε απο το loop πριν το χρησιμοποιησει ... 

Όχι δεν το καταλαβαίνει. Η εκχώρηση μνήμης γίνεται (ή τουλάχιστον έτσι πρέπει) την στιγμή της δήλωσης και όχι τη στιγμή της χρήσης οπότε εκχωρείς 0 bytes μνήμης.

11 ώρες πριν, kaliakman είπε

Ναι αυτή είναι σωστή λύση. 

Τώρα, αυτό που λες δεν παίζει σαν σενάριο. Είσαι απλά τυχερός και δεν σκάει. Αν το δοκιμάσεις σε άλλο μηχάνημα ή αύριο μπορεί να σκάει συνέχεια.

Ούτε αυτό είναι η σωστή λύση. Αφενός πειράζει το όρισμα argv[τάδε]. Αυτό δεν απαγορεύεται φυσικά αλλά έτσι όπως διαβάζω την άσκηση την ερμηνεύω ότι είτε πρέπει να χρησιμοποιηθεί νέα  μεταβλητή στην οποία να αντιγραφεί το argv ή να χρησιμοποιηθεί η toupper μέσα στην printf ώστε να εκτυπωθεί κατευθείαν η έξοδος της toupper. Μπορεί φυσικά η ερμηνεία μου να είναι λάθος.

Ένα άλλο πρόβλημα είναι ότι δεν ελέγχει το πλήθος των παραμέτρων. Αν το πρόγραμμα εκτελεστεί χωρίς παραμέτρους, τότε το for του ξεκινά από i = 1 μέχρι argc (δηλαδή 0) οπότε ακυρώνεται το for και εκτελείται το επόμενο κομμάτι του κώδικα με το pos_max να έχει την αρχική του τιμή 0 δηλαδή εμφανίζεται με κεφαλαία το όνομα του εκτελέσιμου. Και αυτό επίσης είναι δική μου ερμηνεία της άσκησης αλλά θεωρώ ότι δεν θέλει αυτό η άσκηση.

4 ώρες πριν, nek1313 είπε

@kaliakman

Πιστευω οτι δε σκαει σε κανενα μηχανημα το συγκεκριμενο , και το ξερω οτι  δεν ειμαι και  καλος στη C .

Γιατί δεν κάνεις ένα τεστ; Δεν χρειάζεται ούτε σε άλλη αρχιτεκτονική να πας, όπως πρότεινε ο kaliakman, ούτε τίποτα. Τρέξε το πρόγραμμά σου με ολοένα μεγαλύτερο όρισμα και δες τι θα κάνει. Τρέξε το με όρισμα Tria, μετά με TriaPoulakia, μετά με TriaPoulakiaKa8ontai και ούτω καθεξής.

% gcc -Wall -O0 -o tmp tmp.c  
% for i in $(seq 1 100); do  
echo running with argument of $i characters
./tmp $(printf %${i}s | tr " " "a")
if [ $? != 0 ]; then
echo error
break
fi
done

running with argument of 1 characters
A 
running with argument of 2 characters
AA 
...
running with argument of 15 characters
AAAAAAAAAAAAAAA 
running with argument of 16 characters
error

% clang -O0 -o tmp tmp.c 
% for i in $(seq 1 100); do
echo running with argument of $i characters
./tmp $(printf %${i}s | tr " " "a")
if [ $? != 0 ]; then
echo error
break
fi
done
running with argument of 1 characters
A 
running with argument of 2 characters
AA 
...
running with argument of 8 characters
AAAAAAAAP-Nü� 
running with argument of 9 characters
AAAAAAAA '`³ý� 
running with argument of 10 characters
AAAAAAAAÀÔ"Rý� 
running with argument of 11 characters
AAAAAAAAÀ4äAý� 
running with argument of 12 characters
AAAAAAAA`,ñZü� 
running with argument of 13 characters
AAAAAAAA`)P4ý� 
running with argument of 14 characters
AAAAAAAAðTþ� 
running with argument of 15 characters
AAAAAAAAà.ü� 
running with argument of 16 characters
error

% dmesg
[15682.866007] tmp[5348]: segfault at 7ffe17006161 ip 00000000004012e6 sp 00007ffe177751b0 error 4 in tmp[401000+1000]

Το παραπάνω απλό scriptάκι τρέχει τον κώδικά σου δίνοντάς του μία ποσότητα από μικρά άλφα σαν όρισμα. Μεταγλώττισα τον κώδικά σου και με gcc και με clang. Όπως βλέπεις, αρχικά όλα φαίνονται να λειτουργούν καλά και "δεν σκάει" όπως είπες, τουλάχιστον στην αρχή. Γιατί γίνεται αυτό;

Γιατί όπως και στις άλλες εκχωρήσεις μνήμης, ο compiler δεν εκχωρεί όσο του ζήτησες (εν προκειμένω 0) αλλά εκχωρεί ό,τι τον βολεύει αυτόν οπότε μπορεί πχ να εκχώρησε 10 bytes και έτσι μέχρι ένα σημείο έχεις μνήμη για να γράψεις και φαίνεται να δουλεύει. Ή μπορεί να εκχωρεί όντως 0 bytes αλλά να υπάρχουν κάποια padding bytes για άλλες μεταβλητές οπότε να γράφεις εκεί και να μην φαίνεται ότι υπάρχει πρόβλημα. Γράφοντας όμως 16 bytes σκάνε και ο gcc και ο clang με τον 2ο να έχει προβλήματα από πολύ πριν και να εμφανίζει σκουπίδια. Σε 32bit μεταγλώττιση και οι δύο κόλλησαν στα 8 bytes.

Αν χρησιμοποιήσεις optimizations, τότε παράγεται διαφορετικός κώδικας και μπορεί να κρεμάσει σε άλλο σημείο. Σε εμένα με Ο2 ο gcc κρεμάει στα 45 bytes και ο clang κολλάει κατευθείαν στο 1 byte :)

Με άλλα λόγια, το γεγονός ότι δεν το παρατήρησες να σκάει, δεν σημαίνει ότι δεν σκάει κιόλας. Να είσαι 100% σίγουρος ότι κάποια στιγμή θα σκάσει.

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

7 λεπτά πριν, imitheos είπε

....

Αρχικά και εγώ αν είδες πρότεινα απευθείας το αποτέλεσμα της toupper στο printf αλλά ο TS προτίμησε να αλλάξει το όρισμα. Όσο για το δεύτερο που αναφέρεις οι γνώμες διίστανται μιας και θεωρητικά το πρόγραμμα "είναι" argument. Προφανώς δεν έχει νόημα αυτή η συζήτηση αφού ο ΤS δεν έχει ξεκαθαρίσει αλλά θέματα αλλά να 'χαμε να λέγαμε.

Επίσης ενδιαφέρον που με O2 ο gcc δεν σκάει σε δύναμη του 2.:)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • 3 χρόνια αργότερα...
Στις 14/11/2018 στις 2:15 ΠΜ, nek1313 είπε


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

int main(int argc , char *argv[])
{
	
	int i ;
	int pos_max = 0 ;
	int max = 0 ; 
	int c = 0 ; 
	
	for (i = 1 ; i < argc ; i++)
	{	if (strlen(argv[i]) > max)
		{
			max = strlen(argv[i]);
			pos_max = i ;
		}
	}
	while (argv[pos_max][c])
	{
		argv[pos_max][c] = toupper(argv[pos_max][c]);
		c ++;
	}
	printf("%s \n" , argv[pos_max]) ;
	return 0;
}

μαλλον αυτο προτεινεις , τη malloc καλυτερα να την αποφυγω σε αυτο αφου δεν ειναι αναγκαια .

παντως η εξεταση ηταν τρεχει (10)/ δε τρεχει(0) , οποτε αν εγραφα το παραπανω με strcpy  (βγαζει οσες φορες δοκιμασα σωστο αποτελεσμα) 10 θα μου εβαζε !

για καποιο  λογο η C το  καταλαβαινει το  char s[max] και το αρχικοποιει με max = τη τιμη που βγηκε απο το loop πριν το χρησιμοποιησει ... 

 

Χαίρετε,

παρατηρώ το τελικό κώδικα του αρχικού συντάκτη @nek1313 και τις βελτιώσεις που προτείνατε οι @imitheos & @kaliakman και πιο συγκεκριμένα το να χρησιμοποιήσει μέσα στην printf την toupper για τους ευνόητους λόγους. Πως θα μπορούσε όμως να το κάνει κάποιος αυτό, αφού η toupper είναι μέσα σε βρόχο και όπως επισημάνθηκε χωρίς να χρησιμοποιηθεί κάποια προσωρινή μεταβλητή; Μπορεί η όλη λειτουργικότητα ενός βρόχoυ να μπει μέσα σε ένα printf; Αν ναι, πως ακριβώς γίνεται; 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...