-2

So, i am trying to implement my own strcpy to have a better understanding of how pointers work in C, and so far i am at a loss. I tried a lot of different approaches, tried using code from the net to maybe base mine on later, but even those wont work.

I believe i might be calling the function in the wrong way on the main method. I am passing a pointer of the variable to the function, so that the function can change the value of the variable and on the function call, i am giving the adress of the pointer so the method can get the correct data. At least i believe this is how it works, from what i could understand at any rate.

Here are the functions and the method calls:

Function call:

void my_strcpy( char *dest, const char* src ) {

dest = malloc(sizeof(src));

while ( src != '\0' ) {
  *dest = *src;
  src++;
  dest++;
 }

}

Main:

int main () {

const char* s = "Hello World";
char* test = 'd';

my_strcpy( &test, &s ); // Suposed to change test form d to Hello World.
printf("Changed String: " );
printf( "%c", test );


return 0;
}

PS: I tried using test as a string bigger than s to see if it was a memory allocation problem but it does not appear to be so. Any help is greatly apreciated as i have been stuck in this for hours...

PS: I've looked into the question and examples of how to change the variable and can do it using a simple int. But i cannot do it when using char*. Hence the post. I apologize if the issue is the same but i just cannot understand what i'm doing wrong here. Please, have patience with me as i am a beginner in C.

Miyh0
  • 49
  • 1
  • 7
  • 1
    What is `torta` at the first place? – glglgl Apr 04 '15 at 05:44
  • Whoops. Sorry, forgot to change the variable name when copying the code to the question in the site. Will be edditing so it is correct. Torta was the name i was using in my program and i changed to the website for it to make some sort of sense. Thanks for the heads up. – Miyh0 Apr 04 '15 at 06:06
  • You need to spend many hours reading more about C programming and heap memory allocation. It looks like you don't understand what you are coding, and this is always bad. – Basile Starynkevitch Apr 04 '15 at 06:25
  • So many downvoters for a guy with simple question for which SO was really originally meant. I know he could have researched this on his own or probably found similar questions, but if he knew enough to formulate the phrase of the question juanchopanza mentions, he would have been much further ahead than he was when he asked this question. Next, it'll be revenge downvoting my answer by the high priests. – Motomotes Apr 04 '15 at 06:26
  • @Miyh0 You can't do it with a simple int for the same reason you can't do it with a `char*`. – juanchopanza Apr 04 '15 at 06:30
  • 1
    @juanchopanza I think he's attempting to say he did it with an `int` by using `int *` but couldn't do it with `char *` using `char *` becuase he didn't understand the concept of `char **`. – Motomotes Apr 04 '15 at 06:32
  • I have done with int and it works. But every time i try with char* i just get a error and the c program stops ( Better explanation as a comment to the answer below ). I cannot change the function parameters ( Part of the exercise ) so it cannot be a char** as a receiving parameter for the function my_strcpy. – Miyh0 Apr 04 '15 at 06:38
  • I managed to get it working and understood what i was doing wrong! Again, to avoid the same comment twice, the originals are on the answer now marked as the accepted answer. Thanks for the comments as well and i apologize for the lack of knowledge. This is what i am studying for. Hopefully i'll be able to fully understand the language one day. – Miyh0 Apr 04 '15 at 06:56
  • @Miyh0 No, it wouldn't work with `int`, period. You must have confused yourself with something else. There aren't special rules for int. Arguments are passed by value, end of. – juanchopanza Apr 04 '15 at 07:22
  • I dont see the need to be rude but let me explain better. I saw the example with the int that you linked and i made a function that does the same extact thing with the int ( recieves a int and changes its value ). When applying the same thing to char* i was getting a execution time error that had nothing to do with it. I had tried the correct solution before but was not working due to a bad function call in the main method due to a misunderstood of how C handles memory. – Miyh0 Apr 04 '15 at 08:13

2 Answers2

2

The key point is that arguments are passed by value in C.

Hence any change of a formal argument is never seen by the caller function.

At last, your my_strcpy is not behaving like the standard strcpy (which does not allocate memory using malloc). And your use of malloc is wrong, since sizeof(src) is always sizeof(char*) (i.e. 8 on Linux/x86-64).

Here is a better version:

 void my_strcpy( char *dest, const char* src ) {
   while ( *src != '\0' ) {
     *dest = *src;
     src++;
     dest++;
   }
   *dest = '\0'; // zero terminate the string
 }

Notice that strcpy (and my_strcpy) is intrinsically dangerous because you may have buffer overflow (so use strncpy more often). A typical use case would be

 char buf[80];
 my_strcpy(buf, "hello I am here");

so we have local memory (on the call stack typically) and we copy into it. If the literal string was very long (e.g. more than 80 characters) we would have a buffer overflow.

BTW, your test while(src != '\0') was very wrong. A pointer is not the same the pointed value. Your wrong test would typically loop a billion times on a 32 bits machine and would crash before reaching the terminating condition src == NULL

Also in practice strcpy is often known by optimizing compilers like GCC which may even generate a loop, not a function call to a standard function, when compiling it.

Several of your mistakes would probably have been spotted by your compiler (e.g. GCC) if you enable all warnings in your compiler (which you always should), so compile e.g. with gcc -Wall -Wextra -g (to get all warnings, some more, and debug information) then use the debugger gdb to run your program step by step.

In practice, when possible, have functions returning pointers, like

 char* my_almost_strdup(const char*src) {
    size_t ln = strlen(src);
    char* newptr = malloc(ln+1);
    if (!newptr) { perror("my_strdup"); exit(EXIT_FAILURE); };
    strcpy (newptr, src);
    return newptr;
 }

this is a bit like the standard strdup except that I am catching the out-of-memory error case (when malloc fails). It is common to just show some error message and exit in that failing case, but you should always handle malloc failure

Read more about C dynamic memory management and document your memory conventions (when having a function allocating memory in heap thru malloc or calloc etc... you need to document who is in charge of freeing it and how).

Be afraid of undefined behavior and of memory leaks. Use valgrind if available.

Read a bit more about garbage collection (it is a very useful terminology and concept). You might want to code some C programs using Boehm conservative garbage collector (but using Boehm's GC is a whole program decision).

In your main

 my_strcpy( &test, &s ); // VERY BAD

is many times wrong (undefined behavior because of buffer overflow). You should pass an address of a memory zone able to contain the string (including its terminating zero byte), and the second argument does not have the right type (&s is a char** not a const char*).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • I understand the error i made on the condition. The memory allocation was something i was trying to do to see if i could get it to work... As said before, i've been at this for hours. Also, when running the example you gave me, it won't run. Everytime i try to do it i just get a execution time error, return 255, "project.c" ( Name of the file ) stopped working. Initially i thought this could be something wrong with my gcc compiler so i installed codeblocks to see if it helped but it still does the same thing... You know anything i can do to get this working? Thanks for the quick reply! – Miyh0 Apr 04 '15 at 06:10
  • How are you calling `my_strcpy`? The destination argument should be some *existing* pointer (to a sufficiently large memory zone) or array – Basile Starynkevitch Apr 04 '15 at 06:17
  • The same way i've been calling it before but with the adress removed. Just like: my_strcpy( test, s ); Reminder: s has Hello World and test has test. The same thing happens when i increase the size of test to a higher size than s. – Miyh0 Apr 04 '15 at 06:22
  • I see what i was doing wrong! I believe at least. I was passing test when test was being initialized as char* test = "test"; . So the memory space that the variable test points to, is already written. It works when i initialize test as char test[80]; . I'll keep messing arround to see if i can find what i need to do to pass a already initialized char* to thhe function and have it work. Thanks for the repply everyone! – Miyh0 Apr 04 '15 at 06:54
1

You don't need the & to reference the char * because it is already a pointer to a character, you don't want char ** which is a pointer to a pointer to a character.

I patched it up:

void my_strcpy(char** dest, const char* src) {
    const char * srcTemp = src;
    int i = 1; //+1 for null char
    while (*srcTemp != '\0') {
        srcTemp++;
        i++;
    }
    char * destTemp = (char*)malloc(sizeof(char)*i);
    *dest = destTemp;

    while (*src != '\0') {
        *destTemp = *src;
        src++;
        *destTemp++;
    }
    *destTemp = *src; //copy null char

}

int _tmain(int argc, _TCHAR* argv[])
{
    const char* s = "Hello World";
    char* test = 0;

    my_strcpy(&test, s); // Suposed to change test form d to Hello World.
    printf("Changed String: ");
    printf("%s", test);


    return 0;
}
Motomotes
  • 4,111
  • 1
  • 25
  • 24
  • If the function is to allocate memory then it would need that (or equivalent) – M.M Apr 04 '15 at 05:55
  • Right I just realized this. He does want `dest` to be `char **`. – Motomotes Apr 04 '15 at 05:58
  • Thanks for the answer but sadly i cannot change the parameters for the function my_strcpy ( Excercise claims it must be char* dest, char*src ). So the problem remains... But that did gave me a better understanding about pointers. Thank you! – Miyh0 Apr 04 '15 at 06:45
  • Then move the part that counts the characters in the src string as well as the call to `malloc()` outside the function, before the function call in `main()`. I will leave that as an exercise to you. Then you can change the `char **` to `char *` and you wont need `destTemp`. And one last tip, to highlight in-line code in comments surround code by \` key. : ) – Motomotes Apr 04 '15 at 07:05