C: Crea la tua versione di strncpy

Sto lavorando alla creazione della mia versione di strncpy . Il mio codice sembra accettare l’ammenda dell’input, ma il programma termina dopo aver inserito l’input. strncpy sembra anche strncpy la funzione copiata di null se è più corta della prima – che senso ha e come posso implementarla nel mio codice?

 #include  #include  #define SIZE 50 #define STOP "quit" char *copywords(char *str1, char *str2, int n); int main(void) { char words[SIZE]; char newwords[SIZE]; int num; int i = 0; int j = 0; printf("Type a word, and the # of chars to copy, or type 'quit' to quit: "); fgets(words, SIZE, stdin); scanf_s("%d", &num); if (words == STOP) { printf("Good bye!\n"); return 0; } copywords(words, newwords, num); printf("The word was"); puts(words); printf("and the copied word is"); puts(newwords); } char *copywords(char *str1, char *str2, int n) { int i; for (i = 0; i < n; i++) { str2[i] = str1[i]; } return str2; } 

La risposta breve è: NON USARE strncpy() .

Puoi leggere il perché qui: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

La semantica di strncpy è oscura, ampiamente fraintesa e soggetta a errori. L’argomento dimensione è la dimensione della matrice di destinazione , non un certo limite al numero di caratteri da copiare dalla sorgente. Se la lunghezza della stringa di origine è di size o maggiore, la destinazione non verrà terminata con null e se è più corta, il resto della destinazione verrà riempito con byte null ( '\0' ).

Le ragioni di queste scelte sono storiche: strncpy() stato usato per copiare i nomi dei file in una struttura di memoria per un file system arcaico dove i nomi dei file erano di lunghezza limitata.

La mancanza di terminazione nullo è talmente incline all’errore che questa funzione non dovrebbe mai essere usata nel codice di produzione, perché il programmatore o il manutentore fin troppo facilmente fraintendono il comportamento effettivo del codice e creano bug modificandolo.

Se è necessario ri-implementarlo come compito, è necessario implementare la semantica esatta . Si desidera semplicemente avere una comoda funzione di stringa che copia una stringa con troncamento, scegliere un nome diverso e probabilmente un ordine di argomenti diverso.

Ecco alcuni esempi di entrambi:

 char *strncpy_reimplemented(char *dest, const char *src, size_t n) { size_t i; for (i = 0; i < n && src[i] != '\0'; i++) { dest[i] = src[i]; } while (i < n) { dest[i++] = '\0'; } return dest; } char *pstrcpy(char *dest, size_t size, const char *src) { size_t i; if (size > 0) { for (i = 0; i < size - 1 && src[i] != '\0'; i++) { dest[i] = src[i]; } dest[i] = '\0'; } return dest; } 

La tua funzione di copywords ha problemi:

  • Non si annulla la destinazione se la stringa di origine è più lunga di size-1
  • Si denega la stringa di origine oltre la sua lunghezza se è inferiore alla size-1
  • Non si controlla se il valore digitato dall'utente rientra nei limiti corretti per l'origine e gli array di destinazione.

Hai ulteriori problemi:

  • (words == STOP) non controlla se la stringa letta da fgets() viene quit . È necessario prima rimuovere la nuova riga finale dal buffer e utilizzare strcmp() per confrontare le stringhe:

     words[strcspn(words, "\n")] = '\0'; if (!strcmp(words, "quit")) { printf("Good bye!\n"); return 0; } 

Ecco una versione corretta e semplificata del tuo codice:

 #include  #include  #include  char *copywords(char *dest, const char *source, size_t n); int main(void) { char words[50]; char newwords[50]; int num; for (;;) { printf("Type a word, or type 'quit' to quit: "); if (scanf("%49s", words) != 1) { printf("Invalid input!\n"); return 0; } if (!strcmp(words, "quit")) { printf("Good bye!\n"); return 0; } printf("Type the # of chars to copy: "); if (scanf("%d", &num) != 1) { printf("Invalid input!\n"); return 0; } copywords(newwords, words, num); printf("The word was %s\n", words); printf("and the copied word is %s\n", newwords); } } char *copywords(char *dest, const char *source, size_t n) { size_t i; for (i = 0; i < n && source[i] != '\0'; i++) { dest[i] = source[i]; } dest[i] = '\0'; return dest; } 

Problema: non aggiungi caratteri di terminazione alla fine della tua puntura dopo la copia

 for (i = 0; i < n; i++) { str2[i] = str1[i]; } str2[i] = '\0'; 

Perché stai restituendo str2 se non lo stai usando?

Anche io penso che tu abbia bisogno di un par di confronto con l'operatore ==

Modificare:

Codice completo

 #include  #include  #define SIZE 50 #define STOP "quit" void copywords(char *str1, char *str2, int n); int main(void) { char words[SIZE]; char newwords[SIZE]; int num; int i = 0; int j = 0; printf("Type a word, and the # of chars to copy, or type “quit” to quit: "); fgets(words, SIZE, stdin); scanf("%d", &num); copywords(words, newwords, num); printf("The word was "); puts(words); printf("and the copied word is "); puts(newwords); return 0; } void copywords(char *str1, char *str2, int n) { int i; for (i = 0; i < n; i++) { str2[i] = str1[i]; } str2[i] = '\0'; }