我正在努力创建自己的strncpy
版本。我的代码似乎接受输入罚款,但是该程序在输入后终止。如果strncpy
比第一个短,则似乎还可以用nulls将复制函数粘贴到nulls中 - 这是什么意思,我如何在代码中实现它?
#include <stdio.h>
#include <stdlib.h>
#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
或更大,则目的地将 null终止,并且较短,目的地的其余部分将为填充带有null bytes( ' '
)。
这些选择的原因是历史性的:strncpy()
用于将文件名复制到古老文件系统的存储结构中,该系统长度有限。
缺乏零终止是因此,错误易于,此功能在生产代码中永远不会使用,因为程序员或维护者会很容易误解该代码的代码,因为实际行为并通过修改错误来创建错误。
如果您必须作为分配重新实现它,则必须实现 exker 语义。您只想拥有一个方便的字符串函数,该函数将字符串复制带有截断的字符串,选择其他名称和可能的参数顺序。
这是两者的示例:
char *strncpy_reimplemented(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != ' '; i++) {
dest[i] = src[i];
}
while (i < n) {
dest[i++] = ' ';
}
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] != ' '; i++) {
dest[i] = src[i];
}
dest[i] = ' ';
}
return dest;
}
您的copywords
功能有问题:
- 如果源字符串长于
size-1
,则不会终止目标 - 如果源字符串短于
size-1
,则将源字符串超出其长度 - 您不检查用户键入的值是否在源和目标数组的适当范围内。
您还有其他问题:
(words == STOP)
不检查fgets()
读取的字符串是否为quit
。您必须首先从缓冲区中删除尾随的新线,然后使用strcmp()
比较字符串:words[strcspn(words, "n")] = ' '; if (!strcmp(words, "quit")) { printf("Good bye!n"); return 0; }
这是您的代码的更正和简化版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 %sn", words);
printf("and the copied word is %sn", newwords);
}
}
char *copywords(char *dest, const char *source, size_t n) {
size_t i;
for (i = 0; i < n && source[i] != ' '; i++) {
dest[i] = source[i];
}
dest[i] = ' ';
return dest;
}
问题是您在复制
后不会在刺痛结束时添加终止字符for (i = 0; i < n; i++)
{
str2[i] = str1[i];
}
str2[i] = ' ';
如果您使用它,为什么要返回str2?
我也认为您需要不能比较==操作员
编辑:
完整代码
#include <stdio.h>
#include <stdlib.h>
#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] = ' ';
}
eh。我永远不会建议写作"聪明"。赞成"明确"的代码代码,但这是滥用循环以实现strncpy()
的示例:
char *my_strncpy(char *dst, const char *src, size_t n) {
char *d;
size_t i;
for (i=0, d=dst; i<n; i++, *d++ = (*src == ' ') ? ' ' : *src++) { }
return dst;
}
复合表达式,利用短路的三元逻辑,"将所有内容都放在for循环中,而不是将其放在身体中。不要去那里!