C: Создайте собственную версию strncpy

Я работаю над созданием собственной версии strncpy . Мой код, кажется, принимает ввод штрафа, но программа завершается после ввода ввода. strncpy также, кажется, накладывает скопированную функцию с нулями, если она короче первой – в чем смысл этого и как это реализовать в моем коде?

 #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; } 

Короткий ответ: НЕ ИСПОЛЬЗУЙТЕ strncpy() .

Вы можете прочитать, почему здесь: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

Семантика strncpy неясна, широко непонятна и подвержена ошибкам. Аргумент размера – это размер целевого массива, а не некоторое ограничение на количество символов для копирования из источника. Если длина исходной строки имеет size или больше, назначение не будет завершено нулем, а если оно короче, остаток адресата будет заполнен нулевыми байтами ( '\0' ).

Причины этих выборов исторические: strncpy() использовалась для копирования имен файлов в структуру памяти для архаичной файловой системы, где имена файлов были ограничены по длине.

Отсутствие нулевого завершения настолько подвержено ошибкам, что эта функция никогда не должна использоваться в производственном коде, поскольку программист или сопровождающий слишком легко неправильно понимают фактическое поведение кода и создают ошибки, изменяя его.

Если вы должны повторно реализовать его как назначение, вы должны реализовать точную семантику. Это вы просто хотите иметь удобную строчную функцию, которая копирует строку с усечением, выбирает другое имя и, возможно, другой порядок аргументов.

Вот примеры обоих:

 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; } 

У вашей функции copywords есть проблемы:

  • У вас нет значения null для завершения назначения, если длина строки источника больше, чем size-1
  • Вы разыскиваете исходную строку за ее пределами, если она меньше size-1
  • Вы не проверяете, находится ли значение, введенное пользователем, в правильных границах для исходного и целевого массивов.

У вас есть дополнительные проблемы:

  • (words == STOP) не проверяет, quit ли строка, прочитанная fgets() . Сначала вы должны удалить strcmp() из буфера и использовать strcmp() для сравнения строк:

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

Вот скорректированная и упрощенная версия вашего кода:

 #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; } 

Проблема в том, что вы не добавляете завершающий символ в конце вашего жало после копирования

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

Почему вы возвращаете str2, если вы используете его?

Кроме того, я думаю, что вам не нужно сравнивать оператор ==

Редактировать:

Полный код

 #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'; }