Λοιπόν, υπάρχει ένα θέμα παιδιά με την strncpy, για αυτό δεν ήθελα να ξεκινήσουμε από αυτήν. Συγκεκριμένα, αν οι χαρακτήρες του source string είναι περισσότεροι από το n, τότε το destination string ΔΕΝ τερματίζεται με τον μηδενικό χαρακτήρα (και άρα παύει να είναι έγκυρο c-string).
Για να το διαπιστώσετε και μόνοι σας δοκιμάστε τον παρακάτω κώδικα:
- Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h>
int main( void )
{
char src[] = "56789";
char dst[] = "123";
size_t n = 2;
strncpy(dst, src, n);
puts( dst );
return 0;
}
Θα δείτε πως το puts( dst ) δεν θα τυπώσει "56" όπως θα περιμέναμε, αλλά θα τυπώσει "563". Δηλαδή, παίρνει τους 2 πρώτους χαρακτήρες από το src ("56") και τους αντιγράφει στις 2 πρώτες θέσεις του dst, αλλά δεν βάζει '\0', οπότε ο 3ος χαρακτήρας του dst παραμένει αυτός που ήταν από πριν, δηλαδή ο '3'.
Δοκιμάστε επίσης με n = 4 που είναι το μέγιστο μήκος του dst {'1', '2', '3', '\0'} και τα πράγματα γίνονται ακόμα χειρότερα, διότι θα αντιγραφεί το "5678" από το src στο dst, αλλά το '8' θα αντικαταστήσει το '\0' που βρισκόταν στο τέλος του dst πριν την αντιγραφή. Το αποτέλεσμα θα είναι να δημιουργηθεί ένα string dst το οποίο δεν θα έχει πουθενά μηδενικό χαρακτήρα, άρα δεν θα τελειώνει (στην πραγματικότητα θα συνεχίζει κι έξω από τα όριά του μέχρι να βρεθεί τυχαία κάπου στη μνήμη ένας μηδενικός χαρακτήρας).
Μια λύση που έρχεται στο μυαλό πρώτη είναι να προσθέτουμε ένα '\0' μετά την αντιγραφή, αλλά και πάλι αν το n ισούται με το μέγιστο μήκος του dst, τότε αυτό το '\0' που θα προσθέσουμε θα βγει έξω από τα όρια του dst (και άρα θα μηδενίσει ένα byte στη μνήμη, το οποίο δεν ανήκει στο dst! Δηλαδή, στο παράδειγμά μας, αν το n=4 κι εμείς προσθέτουμε ένα '\0' μετά την αντιγραφή των 4 πρώτων χαρακτήρων από το src στο dst, αυτό το 'έξτρα \0' θα μπει στην 5η θέση του dst η οποία πολύ απλά ΔΕΝ υπάρχει (η τελευταία θέση του dst όπως το έχουμε ορίσει είναι η 4η, η οποία οφείλει να φιλοξενεί έναν μηδενικό χαρακτήρα).
Στη δική μου υλοποίηση της strncpy (την οποία δεν θα σας τη δώσω ακόμα) αυτό που κάνω είναι να αντιγράφω όχι τους n πρώτους χαρακτήρες του src στο dst, αλλά τους n-1 χαρακτήρες! Στη θέση n βάζω πάντα τον μηδενικό χαρακτήρα. Άρα λοιπόν στη δική μου υλοποίηση το n περιλαμβάνει και τον μηδενικό χαρακτήρα, που με άλλα λόγια σημαίνει πως αντιγράφει n-1 ωφέλιμους χαρακτήρες και όχι n.
Προφανώς αν το n είναι μεγαλύτερο από το μέγιστο μήκος του dst (δλδ από 5 και πάνω στο παράδειγμά μας) το πρόβλημα επανέρχεται, αλλά αυτό το πρόβλημα υπάρχει και στην στάνταρ strncpy.
Η λύση είναι μέσα στη συνάρτηση μας να υπολογίζουμε πρώτα το μέγιστο μέγεθος του dst: sizeof( dst ) ή να το περνάμε σαν όρισμα στη συνάρτηση, και κατόπιν να το χρησιμοποιούμε στους ελέγχους που κάνουμε στο κύριο loop της συνάρτησης, φροντίζοντας η αντιγραφή από το src στο dst να περιορίζεται όχι από n αλλά από το μικρότερο νούμερο μεταξύ των n και sizeof( dst ).
Όταν δώσω τη δική μου λύση, θα έχω δυο εκδοχές της συνάρτησης: μια που δεν θα κάνει έλεγχο για το μέγιστο μήκος του dst και μια που θα κάνει.
Φίλε Σταματίου, η δική σου λύση "υποφέρει" από το έξτρα '\0' που προσθέτεις μετά την αντιγραφή των n χαρακτήρων, γιατί στην περίπτωση που το n ισούται με το μέγιστο μήκος του dst, ο έξτρα αυτός χαρακτήρας βγαίνει εκτός ορίων του dst.
Φίλε Star_Light, η δική σου λύση δεν υλοποιεί την strncpy, αλλά την strcpy (που δεν έχει n) οπότε θα την κοιτάξω λεπτομερώς όταν θα τη φτιάξει με το n. Επίσης, για να μη παιδεύεσαι, μη ζητάς τα strings από την κύρια είσοδο... όρισέ τα εσύ απευθείας μέσα στη main όπως κάνει ο φίλος Σταματίου ή όπως κάνω εγώ στο κώδικα που έδωσα πιο πάνω σε αυτό το post.
Επίσης, αυτό εδώ...
- Κώδικας: Επιλογή όλων
printf("Dwse mia sumvoloseira: ");
fgets(s2,255,stdin);
sscanf(s2,"%c",s2);
σου έχω εξηγήσει τουλάχιστον 2 φορές από ότι θυμάμαι πως είναι λάθος και γιατί είναι λάθος !

Αφενός το %c αναφέρεται σε χαρακτήρα και εσύ το χρησιμοποιείς για string, αφετέρου στην scanf δεν μπορείς να έχεις το 1ο της όρισμα σε άλλα ορίσματα κι αφετρίτου

για να διαβάζεις σκέτα strings δεν χρειάζεσαι τη scanf... χρειάζεσαι ή την fgets (και να πας να μηδενίσεις το '\n' μετά στο τέλος του string) ή την s_get ή την s_getflushed (αυτές οι 2 τελευταίες δεν βάζουν '\n' στο τέλος του string που διαβάζουν).