C: Create own version of strncpy

旧街凉风 提交于 2019-12-11 06:38:04

问题


I am working on creating my own version of strncpy. My code seems to accept the input fine, but the program terminates after the input is entered. strncpy also seems to pad the copied function with nulls if it's shorter than the first - what is the point of that and how do I implement that in my code?

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

回答1:


The short answer is: DO NOT USE strncpy().

You can read why here: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

The semantics of strncpy are obscure, widely misunderstood and error prone. The size argument is the size of the destination array, not some limit to the number of characters to copy from the source. If the source string length is size or larger, the destination will not be null terminated and if it is shorter, the remainder of the destination will be filled with null bytes ('\0').

The reasons for these choices are historical: strncpy() was used to copy filenames into a memory structure for an archaic file system where filenames were limited in length.

The lack of null termination is so error prone that this function should never be used in production code, because the programmer or the maintainer will all too easily misunderstand the code's actual behavior and create bugs by modifying it.

If you must re-implement it as an assignment, you must implement the exact semantics. It you just want to have a handy string function that copies a string with truncation, choose a different name and probably a different argument order.

Here are examples of both:

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

Your copywords function has problems:

  • You do not null terminate the destination if the source string is longer than size-1
  • You dereference the source string beyond its length if it is shorter than size-1
  • You do not check if the value typed by the user is within the proper bounds for the source and the destination arrays.

You have further problems:

  • (words == STOP) does not check whether the string read by fgets() is quit. You must first remove the trailing newline from the buffer and use strcmp() to compare strings:

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

Here is a corrected and simplified version of your code:

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



回答2:


Problem is you dont add terminating character at the end of your sting after copying

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

Why are you returning str2 if you arent using it?

Also i think you need cant compare by == operator

Edit:

Full Code

#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] = '\0';
}


来源:https://stackoverflow.com/questions/40834173/c-create-own-version-of-strncpy

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!