C:创建自己的strncpy版本



我正在努力创建自己的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循环中,而不是将其放在身体中。不要去那里!

相关内容

  • 没有找到相关文章

最新更新