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参数是目标数组的大小,而不是从源复制的字符数的某些限制。 如果源字符串长度为size
或更大,则目标将不会以null结尾,如果它更短,则目标的其余部分将填充空字节( '\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
function有问题:
- 如果源字符串长度大于
size-1
则不会终止目标 - 如果源字符串短于
size-1
,则取消引用超出其长度的字符串 - 您不检查用户键入的值是否在源数组和目标数组的适当范围内。
你还有其他问题:
-
(words == STOP)
不检查fgets()
读取的字符串是否quit
。 您必须首先从缓冲区中删除尾部换行符并使用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'; }