1

My task is like this: I should implement the strcpy function under the following constraints:

  1. The function should use pointer expression (*(d+i))
  2. I should implement it without using <string.h>

I'm programming in Visual Studio 2019. I searched some source code in google and run them, but my program has a logical error. The program ends right away, each time. I don't know what I'm doing wrong. Here's my code in Visual Studio 2019 on Windows. Please tell me what's wrong.

#include <stdio.h>
void strcpy(char*, char*);

int main()
{
    char* sen1 = "Hello";
    char* sen2 = "Friends";

    strcpy(sen1, sen2);

    printf("The result: %s\n", sen1);

    return 0;
}

void strcpy(char* str1, char* str2)
{
    int i = 0;
    while (*(str2 + i) != '\0')
    {
        *(str1 + i) = *(str2 + i);
        i++;
    }
    *(str1 + i) = '\0';
}
Jens
  • 69,818
  • 15
  • 125
  • 179
  • Hmmm... What *writable* storage do `sen1` and `sen2` point to? (or are they simply pointers initialized pointing to non-modifiable *String Literals*?) Why not, e.g. `char sen1[64] = "Hello"; char sen2[64] = "Friends";` so both are declared as *arrays*? – David C. Rankin May 02 '20 at 07:19
  • The program hasn't to scan strings and assign sen1 and sen2. So I set up String Literals to them. (And I'm not good at English... So please be kind to understand!) – 올리브한개 May 02 '20 at 07:28
  • Sure, you can simulate your *source* (`sen2`) string with a string literal for testing, but your pointer for `sen1` must point to valid storage that you can write to (like a character array long enough to hold `sen1` (plus the nul-terminating character). – David C. Rankin May 02 '20 at 07:41
  • I believe this question is a duplicate of [strcpy using pointers](https://stackoverflow.com/questions/13460934/strcpy-using-pointers) – Abra May 02 '20 at 07:41
  • @Abra Almost, but not quite. The requirement about avoiding index and using ptr+offset notation makes it sufficiently different, I believe. – Jens May 02 '20 at 07:43

4 Answers4

5

In addition to needing to provide writable storage for sen1, you should also check to ensure str2 != NULL in your function before dereferencing str2 (otherwise, even if you fix all other errors -- a segfault will likely result)

For example, in your code you can define a constant to use in setting the size of a sen1 array (or you can allocate storage with malloc(), calloc(), or realloc() -- save that for later). Using an array you can do, e.g.

#include <stdio.h>
#include <stdlib.h>

#define MAXC 64     /* if you need a constant, #define one (or more) */
...
int main (void)
{
    char sen1[MAXC] = "Hello";
    char *sen2 = "Friends";

    mystrcpy (sen1, sen2);

    printf ("The result: %s\n", sen1);

}

In your strcpy function, check that str2 isn't NULL before using str2 in your function, e.g.

char *mystrcpy (char *dest, const char *src)
{
    char *p = dest;

    if (!src || !dest) {            /* ensure src or dest is not NULL */
        fputs ("error: src or dest parameters NULL in mystrcpy().\n", stderr);
        exit (EXIT_FAILURE);
    }

    do                              /* loop */
        *p++ = *src;                /* copy each char in src to dest */
    while (*src++);                 /* (including the nul-termianting char) */

    return dest;                    /* return pointer to dest */
}

Now you will copy your source string to your destination string in your (renamed) mystrcpy() function, receiving the results you expect:

Example Use/Output

$ ./bin/mystrcpy
The result: Friends

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • I'm not sure if the test ensuring `src` is not NULL is a good idea. If `src` is NULL I'd let the program crash (which will happen on almost all present desktop platforms). I don't think that _actual_ `strcpy` implementation do this check. – Jabberwocky May 02 '20 at 07:53
  • 1
    That's more a check/habit in all functions that take pointers as arguments before dereferencing. You have a good point. An `if (!src) { fputs ("error: NULL source pointer in mystrcpy().\n", stderr); exit (EXIT_FAILURE); }` would be cleaner. Thank you! – David C. Rankin May 02 '20 at 07:58
  • There are some things I haven't learned yet(exit, fputs(maybe a role of printf?)), so I'll have to refer to some of them. But thanks for your kind comment! – 올리브한개 May 02 '20 at 08:17
  • @올리브한개 `exit` is used to stop executing the program from inside of the function. `fputs()` is just a alternative to the `printf()` function especially for printing strings only and in this case exclusive to the error stream `stderr` instead of `stdout` as it is with `printf`. – RobertS supports Monica Cellio May 02 '20 at 08:20
  • I added `#include ` which provides the `exit()` function that allows you to gracefully exit your program from within a function without returning to `main()`. There are only two codes `EXIT_SUCCESS` (value `0`) and `EXIT_FAULURE` (value `1`). `fputs()` is just `puts()` that allows you to output a string to any file (rather than just to `stdout` as `puts()` and `printf()` due by default). You would use `fprintf()` if you required conversions within your *format string*, otherwise, you compile likely substitutes `puts()/fputs()` for you. – David C. Rankin May 02 '20 at 08:20
  • I think it would be useful to also check `dest` for being a `NULL` pointer. If it is, one would write to undefined memory. Also why did you implemented `p`? It seems redundant. – RobertS supports Monica Cellio May 02 '20 at 08:33
  • 1
    Good call on checking `dest` not `NULL` also. `p` allows me to `return dest;`, otherwise the pointer `dest` would be at the end of the string if I was increment it. – David C. Rankin May 02 '20 at 08:36
  • Oh, I fully understand. I think I can use the functions thanks to you. Thank you for your detailed answer. Have a nice day! – 올리브한개 May 02 '20 at 08:37
3

Two problems, at least:

  1. String literals are not writable in C. Often the symptom is a crash (SIGSEGV).
  2. You are not allowed to use the identifier strcpy for your own function. Use another name.

Three clean code issues, at least:

  1. Turn int main() into int main(void) to make it properly typed.
  2. str1 and str2 are too generic names. They don't indicate which is the source and which is the destination pointer. What about my_strcpy(char *dest, char *src)?
  3. I'd use size_t i for the index counter instead of int, because that's the type all the string length functions and the sizeof operator return. It's also an unsigned type and can copy really long strings :-) The size_t is available after #include <stddef.h>.
Jens
  • 69,818
  • 15
  • 125
  • 179
  • (well qualified, at minimum `:)` – David C. Rankin May 02 '20 at 07:24
  • 1. Then should I scan string literals for sen1 and sen2? 2. Do I use another name such as 'mystrcpy'? (And I'm not good at English... So please be kind to understand!) – 올리브한개 May 02 '20 at 07:31
  • @올리브한개 1. No, only the destination needs to be an array, like `char dest[64];`. But it's ok to make both an array. 2. Yes, exactly. – Jens May 02 '20 at 07:35
  • @Jens Thanks for your help!!! I solved my problem. Have a nice day! – 올리브한개 May 02 '20 at 07:48
  • 1
    @올리브한개 Wonderful! The next step on Stackoverflow is to *accept* the answer that helped you most by clicking the check mark to the left. It's okay to wait a day or two for more answers to appear. – Jens May 02 '20 at 07:53
  • @Jens Okay! Thanks for explaining. I'd like to know other ways, so I'll put it off a little bit. :) – 올리브한개 May 02 '20 at 07:54
2

You want this:

...
char* source = "Hello";
// or char source[] = "Hello";
char destination[1000];      // destination buffer long enough for playing around

my_strcpy(destination, source);

printf("%s\n", destination);   // should print "Hello" if my_strcpy is corect
...

For the rest read Jens's answer.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
0

Among the other good answers, just regarding the implementation of your strcpy function and not a detailed issue analyze of your actual code, another approach is this:

char * n_strcpy(char * dest, char const * src)
{
    if (dest == NULL || src == NULL)
    {
        return NULL;
    }

    char *ptr = dest;

    while ((*dest++ = *src++));

    return ptr;
}
  • I did this way, but the error kept happening. However I know that the problem is main() function right now. Thanks! – 올리브한개 May 02 '20 at 08:12
  • This can't possibly work. You're incrementing possibly uninitialized data and const-qualified data. Please test code before posting. And the requirements explicitly stated to not use index notation. – Jens May 02 '20 at 10:34
  • @Jens You was right, me fool. Corrected. But I don´t understand where you trying to point me at with uninitialized data. Do you mean `src`/`dest` itself or `*src` `*dest`, or even `ptr`? – RobertS supports Monica Cellio May 02 '20 at 11:20
  • Because of `dest[i]++`, since dest[] may be uninitialized in the call and you increment each uninitialized character. – Jens May 02 '20 at 11:36