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

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

Δημοσ.

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

int main(void)
{
char str1[]="Copy me";
char str2[]="Copy youuu!!!";

strncpy(str1,str2,sizeof(str1));

puts(str1);

return 0;
}

 

Παραπάνω πως δουλευει η puts αφου στο str1 δεν υπάρχει μετα την αντιγραφή ο μηδενικος χαρακτήρας?

 

Το Copy you που θα υπάρχει στο str1 ειναι 8 χαρακτήρες ο μηδενικος δεν νομιζω οτι υπάρχει καπου αρα η χρηση της puts εδω παράγει UB ?

  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

Δεν δουλεύει η παραπάνω puts()... απλώς τυπώνει χαρακτήρες μέχρι να βρει 0 ή να βαρέσει seg-fault.

 

EDIT

 

Για να την κάνεις να δουλέψει, άλλαξε την strncpy() σε...

 

>
strncpy( str1, str2, sizeof(str1)-1 );

Δημοσ.

Δεν δουλεύει η παραπάνω puts()... απλώς τυπώνει χαρακτήρες μέχρι να βρει 0 ή να βαρέσει seg-fault.

 

EDIT

 

Για να την κάνεις να δουλέψει, άλλαξε την strncpy() σε...

 

>
strncpy( str1, str2, sizeof(str1)-1 );

 

Ναι συμφωνω . Επισης θές και ένα

 

str1[sizeof(str)-1] = '\0'; για το quarantee του null-terminated string. O τελεστης sizeof δινει το μέγιστο μήκος στον πίνακα.

Aπλα εμενα μου εκτύπωσε κανονικα το Copy you η puts για αυτο με εκανε να απορησω

στο δικο σου συστημα μπορει να μην εκτύπωσε τιποτα .

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

...

Επισης θές και ένα

 

str1[sizeof(str)-1] = '\0'; για το quarantee του null-terminated string.

...

 

Όχι, αν το κάνεις αυτό θα κόψεις και τον τελευταίο ωφέλιμο χαρακτήρα του str1. Στη θέση sizeof(str1) υπάρχει έτσι κι αλλιώς 0, από την αρχικοποίηση του str1. EDIT, κατόπιν σωστής υπόδειξης του StarLight... μπέρδεψα το sizeof με την strlen()

 

Για την γενική περίπτωση, η δική μου πρόταση είναι η εξής:

 

>
...
#define MAX_S1LEN  (7+1)

int main( void )
{
   char str1[MAX_S1LEN] = "Copy me";
   char str2[] = "Copy youuu!!!";

   strncpy( str1, str2, MAX_S1LEN-1 );

   puts(str1);

   return 0;
}

 

ή...

 

>
...
#define MAX_S1LEN  (7+1)

int main( void )
{
   char str1[MAX_S1LEN] = {'\0'};
   char str2[] = "Copy youuu!!!";

   strncpy( str1, str2, MAX_S1LEN-1 );

   puts(str1);

   return 0;
}

 

 

 

EDIT

 

Btw, η s_strncpy() σε απαλλάσει από αυτό το πρόβλημα. Απλά της περνάς το sizeof(str1) και τα υπόλοιπα τα κάνει μόνη της ;)

 

...

Aπλα εμενα μου εκτύπωσε κανονικα το Copy you η puts για αυτο με εκανε να απορησω

στο δικο σου συστημα μπορει να μην εκτύπωσε τιποτα .

 

Σε WinXP SP3 o mingw32 gcc 4.7.0 τυπώνει...

 

>
Copy youπX@

 

η PellesC 32bit v7.0 τυπώνει

 

>
Copy youΐ

 

και ο lcc-win32 v3.8 τυπώνει...

 

>
Copy youΔ @

Επεξ/σία από migf1
Δημοσ.

migf1 καλα τα λες απλα επειδη το προτεινει ο King στην σελ.291.

 

Σε ποια εκδοχη κωδικα θα μπορουσε να ειναι εύχρηστο αυτο που προτεινει ο King ?

 

Μηπως σε περιπτωση που χρησιμοποιεις ενα μη αρχικοποιημένο πινακα χαρακτηρων ?

Και τον περνάς σαν ορισμα στην συνάρτηση ? Αλλα γιατι να μην τον αρχικοποιησεις? δεν βρισκω νοημα

σε ολες τις άλλες περιπτώσεις ειτε παραλειποντας τον μεγεθος ειτε οχι ο compiler βαζει εναν '\0' στο τελος εκτος βεβαια και αν περάσεις ενα string με 8 χαρακτηρες το αρχικοποιησεις με 8 και δεν βαλεις πουθενα τον '\0' οποτε θα σου φαει τον εναν η συνάρτηση τον τελευταιο για να βαλει εκει τον μηδενικο.

 

>

#include<stdio.h>
#include<string.h>
#define MAX_S1LEN (7+1)

int main( void )
{
 char str1[MAX_S1LEN];
 char str2[] = "Copy youuu!!!";

 strncpy( str1, str2, sizeof(str1)-1 );
 str1[sizeof(str1) - 1] = '\0';

 puts(str1);

 return 0;
}

Δημοσ.

Ooops, my bad!

 

Έχετε δίκιο (κι εσύ και ο King :)). Εκ παραδρομής υπολόγισα στο μυαλό μου το sizeof σαν να ήταν strlen().

 

Βλακεια πεταξα ζαλιστηκα σορρυ. Το εσβησα ολο το προηγουμενο που έγραψα :P

Ναι ετσι ειναι και δεν τρωει και κανεναν ωφελιμο χαρακτηρα απο το μήκος του str1 !

 

Γιατι κάπως μπακάλικα καταρχην μπορει κάποιος να δει το εξης :

 

>

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

int main( void )
{
 char str1[] = "Copy me";
 char str2[] = "Copy youuu!!!";
 int x;

 strncpy( str1, str2, sizeof(str1) - 1);
 str1[ x= sizeof(str1)-1] = '\0';

 printf("%d\n" , x);

 puts(str1);

 return 0;
}

 

To x ειναι 7. Δηλαδη (0....7) αρα ο 8ος . Ο οποιος συμφωνα με την αρχικοποιηση εξαρχης

ειναι ο μηδενικός. Η θεση αυτη ειναι μονο για αυτον και κανεναν αλλον.

Φυσικα το παραπανω μπορει να μην ειναι καλο σαν τεχνικη για το readability του κωδικα αλλα ενταξει για την δουλεια που το θελουμε τωρα.... ειναι ενταξει.

Δημοσ.

Καθόλου βλακεία δεν πέταξες. Το sizeof(s)-1 είναι όντως η η τελευταία θέση του s (και σε φουλ γεμισμένο s ισούται με strlen(s) ).

Δημοσ.

Καθόλου βλακεία δεν πέταξες. Το sizeof(s)-1 είναι όντως η η τελευταία θέση του s (και σε φουλ γεμισμένο s ισούται με strlen(s) ).

 

Βλακεια εννοω στο οτι εγραψα οτι κοβει καποιον ωφέλιμο.

Απλα η ολη μανουρα γινεται επειδη ο μεταγλωτιστης σιωπηλά και ύπουλα οταν

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

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

 

Τελοςπαντων δεν μπορω να πω οτι έχω καποια σοβαρη απορια που διαβαζω το κεφαλαιο του ως τωρα αλλα καποια πραγματα δεν καταλαβαινω γιατι τα κανει πχ

 

Αυτο εδω γιατι το λεει ->

 

Does the form of the parameter (s[] or *s) affect what can be supplied as an argument ?

No. When count_spaces is called, the argument could be an array name , a pointer variable , or a string literal - count_spaces can't tell the difference .

 

Eπισης γιατι ενω παραθέτει το πρωτοτυπο της συνάρτησης της strcpy με παραμετρους s1 και s2 μεσα μετα τα αλλαζει σε str1 και str2 τοπικα στην συνάρτηση τις μεταβλητες θα τις έγραφες οπως τις οριζεις οχι με αλλα ονοματα

και αυτο που δειχνει το s1 το λεει array ενω το αλλο string (βεβαια με το const μπροστα απευθειας string literal ειναι).

Δημοσ.

Η δική μου πρόταση πάλι είναι να μην χρησιμοποιηθεί καν η strncpy αλλά η memcpy. Η strncpy δεν βγήκε ως secure έκδοση της strcpy αλλά ούτε καν ως συνάρτηση αντιγραφής C-Strings. Εισήχθη για να δουλεύει με fixed-length nul-padded char arrays για αυτό και κάνει pad με nul. Τα παραπάνω είχαν συχνή χρήση στο παρελθόν όπως στα ονόματα αρχείων σε παλιά unix, σε παλιά παιχνίδια για DOS, κτλ.

 

>
00000000  45 4E 44 00 00 00 00 00 00 00 00 00 00 00 00 00 END.............
00000010  00 00 00 00 00 01 50 41 4C 41 44 49 4E 00 00 00 ......PALADIN...

 

Εδώ βλέπουμε την αρχή από ένα savegame ενός παλιού παιχνιδιού. Ο τίτλος του save καταλαμβάνει πάντα 21 bytes και το όνομα του κάθε χαρακτήρα πάντα 11 bytes. Εγώ έδωσα τίτλο END οπότε τα υπόλοιπα πρέπει να γίνουν pad με μηδενικά. Το ίδιο θα βλέπαμε και σε κάποιο παλιό filesystem. Για αυτή τη δουλειά βγήκε η strncpy.

 

Εφόσον στην strncpy πρέπει για σιγουριά να φροντίσουμε εμείς να γράψουμε στο τέλος το 0 και επίσης επειδή λόγω του padding δεν σταματάει όταν βρει μηδέν όπως η strcpy και παρόμοιες, δεν έχουμε κανένα πλεονέκτημα έναντι της χρήσης της memcpy. Η αποφυγή της strncpy είναι κανόνας σε κάμποσα coding styles και μάλιστα η κακή της λειτουργία ήταν η αφορμή για να γράψει το OpenBSD την strlcpy.

 

Η πρότασή μου λοιπόν είναι να ξεχάσουμε την strncpy (ειδικά σε φόρουμ βοήθειας). Να ζήσουμε να τη θυμόμαστε αλλά μακρυά μακρυά :P

Δημοσ.

...

Αυτο εδω γιατι το λεει ->

 

Does the form of the parameter (s[] or *s) affect what can be supplied as an argument ?

No. When count_spaces is called, the argument could be an array name , a pointer variable , or a string literal - count_spaces can't tell the difference .

 

Επειδή όταν πρωτο-ορίζεις ένα string έχει διαφορά αν θα το ορίσεις ως s[] ή ως *s, ενώ όταν το δηλώνεις στην λίστα παραμέρτων μιας συνάρτησης δεν έχει.

 

Eπισης γιατι ενω παραθέτει το πρωτοτυπο της συνάρτησης της strcpy με παραμετρους s1 και s2 μεσα μετα τα αλλαζει σε str1 και str2 τοπικα στην συνάρτηση τις μεταβλητες θα τις έγραφες οπως τις οριζεις οχι με αλλα ονοματα

και αυτο που δειχνει το s1 το λεει array ενω το αλλο string (βεβαια με το const μπροστα απευθειας string literal ειναι).

 

Διότι η δήλωση των προτύπων δεν χρειάζεται καν ονόματα ορισμάτων, μόνο οι τύποι χρειάζονται. Οπότε αν βάλεις και ονόματα μπορεί να είναι ότι θέλεις.

 

...

Η πρότασή μου λοιπόν είναι να ξεχάσουμε την strncpy (ειδικά σε φόρουμ βοήθειας). Να ζήσουμε να τη θυμόμαστε αλλά μακρυά μακρυά :P

 

Αν χρησιμοποιηθεί με τρόπους παραπλήσιους με αυτόν που έδειξα σε προηγούμενο ποστ δεν έχει πρόβλημα. Πλην του ότι σέρνεται :lol:

Δημοσ.

Γαμωτο... παντα μου διαφεύγει αυτο το ερωτηματικό στο τελος και μπερδευω το πρωτοτυπο με τον ορισμο της συνάρτησης.....

 

αφου πολλες φορες κτυπά και ο compiler :P.

 

Τωρα σχετικα με αυτο που επισημανε ο ημιθεος εγω δεν εχω προβλημα να μην χρ/ται η strncpy αλλωστε και ο migf1 εχει να προτεινει μερικες δικες του... αλλα μιας και καποιος δεν θα εχει προχωρησει ακομη στην δυναμικη δεσμευση μνημης και θα βλεπει τα αρχικα δεν βρισκω λαθος να ξεκινησει με αυτην... ειδικα αμα θελει να δει για ποιο λογο δεν πρεπει να την προτιμαει.

 

Παντως και ο King (έχουμε πρηξει κοσμο με αυτον μεγαλη διαφημιση....) την παρουσιαζει σαν πιο ασφαλη απο την προηγουμενη αλλα και πιο αργη.

Δημοσ.

Γαμωτο... παντα μου διαφεύγει αυτο το ερωτηματικό στο τελος και μπερδευω το πρωτοτυπο με τον ορισμο της συνάρτησης.....

 

αφου πολλες φορες κτυπά και ο compiler :P.

 

Εγώ όπως ίσως έχεις ήδη διαπιστώσει από τους κώδικες που δίνω, τα αποφεύγω τα πρότυπα :lol: Ορίζω τις συναρτήσεις με τέτοια σειρά ώστε να μη χρειάζεται δήλωση προτύπων (δεν είναι πάντα εφικτό, αλλά κατά κανόνα το πετυχαίνω)

 

 

Τωρα σχετικα με αυτο που επισημανε ο ημιθεος εγω δεν εχω προβλημα να μην χρ/ται η strncpy αλλωστε και ο migf1 εχει να προτεινει μερικες δικες του... αλλα μιας και καποιος δεν θα εχει προχωρησει ακομη στην δυναμικη δεσμευση μνημης και θα βλεπει τα αρχικα δεν βρισκω λαθος να ξεκινησει με αυτην... ειδικα αμα θελει να δει για ποιο λογο δεν πρεπει να την προτιμαει.

 

Η memcpy() δεν παραπέμπει σε δυναμική δέσμευση μνήμης. Το αντίθετο, τα 2 της πρώτα ορίσματα προϋποθέτουν ήδη δημιουργημένα buffers.

 

Το γεγονός μάλιστα πως το sizeof(char) είναι πάντα 1 (κάτι που κι εγώ το ξεχνάω ενίοτε) σε απελευθερώνει κι από την χειροκίνητη μετατροπή σε bytes για το 3ο της όρισμα.

 

Αλλά με την strncpy() αφενός είναι πιο straight-forward ότι η πρόθεσή σου είναι να αντιγράψεις strings, κι αφετέρου αν όντως χρειάζεσαι nil-padding στο τέλος, μετά την memcpy() πρέπει να γράψεις κι άλλο κώδικα.

Δημοσ.

@migf1 για τσέκαρε λιγο το παρακάτω στον δικο σου compiler :P

 

Πιστευω ειναι εντάξει.

 

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

int main( void )
{
 char str1[10]="Hello";
 char str2[]="Dude";

 printf(" %s\n" , strcat(str1,str2)); // HelloDude
 printf(" %s , %s , %s " , strcpy(str1,str2) , str1 , str2); // Dude , Dude

 return 0;
}

 

Αν δεν έβαζα εξαρχης το 10 στο str1 μολις η strcat άρχιζε δουλειά ο μεταγλωτιστής θα υπολογιζε αυτοματα το μέγιστο μήκος οπως κάνει υπο κανονικές συνθήκες ή οχι?

Δημοσ.

Αν δεν υπάρχει το 10, τότε ο πίνακας str1 θα οριστεί με μέγεθος όσο χρειάζεται για το literal δηλαδή 5 + 1 οπότε η strcat θα έγραφε πάνω σε μνήμη που δεν την ανήκει ή θα βαρούσε segmentation fault. Υπό ποιες "κανονικές" συνθήκες υπολογίζει ο compiler το μέγεθος αυτόματα ?

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

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