-3

I am getting confused with pointers. Here is a code to swap two names. Please see the code. Consider Input : hellohai(for d) and asd(for e). Output i am getting : asd 1ellohai 1ellohai

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

int main()
{
        char *d,*e,*f;


        d=(char*)malloc(10);
        e=(char*)malloc(5);

        scanf("%s",d);
        scanf("%s",e);

        f=d;
        d=e;   
        e=f; //while printing e it prints the whole value contained in f (i.e.1ellohai). How? size of e is 5 only

        f[0]='1'; // f is in read-only memory. So this should fail?
        printf("%s \t %s \t %s \n",d,e,f);


        return 0;
}
Shikhar Deep
  • 253
  • 2
  • 8
  • 19
  • 2
    `f[0]` is *not* readonly. It is assigned `d` which points to malloced memory, which is always writable. – Jens Sep 11 '15 at 13:38
  • so you mean if i do something like f="hello" then only it is in read only. What about the value of e? – Shikhar Deep Sep 11 '15 at 13:40
  • f itself is not readonly, either. – Peter - Reinstate Monica Sep 11 '15 at 13:41
  • 1
    What is the question? – donjuedo Sep 11 '15 at 13:41
  • The size of the thing `e` *originally* pointed to was 5; after the swapping, what it points to is size 10 (what was originally pointed to by `d`). The sizes of `e` and `d` themselves (the pointers) don't change. – Scott Hunter Sep 11 '15 at 13:42
  • Yes; the memory for string literals used to initialize pointer-to-char is readonly (`char *foo="bar"`). It is read/write for arrays-of-char, e.g. `char foo[]="bla";` – Jens Sep 11 '15 at 13:42
  • donjuedo: see the comments inside code – Shikhar Deep Sep 11 '15 at 13:42
  • It works as I would expect it to. `e` originally pointed to the block of 5, and after the pointer swap, `e` points to the block of 10. Vice versa for d. Why do you say `f` is read only? Is it on a custom board and in ROM somehow? For a normal PC, with the code we see, `f` can be changed, as well as the contents `f` points to. – donjuedo Sep 11 '15 at 13:45
  • donjuedo: I thought f is read only because its not malloced. So even if e points to a block of 10, i can't write more than 5bytes inside e(because e's size is 5). Correct me if i am wrong? – Shikhar Deep Sep 11 '15 at 13:48
  • If you do `char *f = "hello";` then (initially) `f` points to memory that you are not supposed to modify. Whether the system will *enforce* that is not specified. A good compiler ought to warn, though, about dropping `const` qualification. The correct declaration would be `const char *f = "hello";`. – John Bollinger Sep 11 '15 at 13:49
  • I've said it before, but [please don't cast the return value of `malloc()` in C](http://stackoverflow.com/a/605858/28169). – unwind Sep 11 '15 at 13:53

4 Answers4

3

When you do this:

    d=(char*)malloc(10);
    e=(char*)malloc(5);

d points to a 10 byte buffer, and e points to a 5 byte buffer.

Then you have this:

    f=d;    // f now points to the 10 byte buffer
    d=e;    // d now points to the 5 byte buffer
    e=f;    // e now points to the 10 byte buffer

You're not actually copying the strings from one to the other. You're really changing the pointers.

Then when you do this:

f[0]='1';

It changes the first byte of the 10 byte buffer. f is not read-only because it is pointing to the same malloc'ed buffer that d originally (and now e) pointed to.

dbush
  • 205,898
  • 23
  • 218
  • 273
3

When you are swapping pointers what you are swapping is the memory location that is in the pointer variable. f has the old value of d and is pointing to the memory allocated via malloc. Therefore

f[0]='1'; // f is in read-only memory. So this should fail?

Is incorrect.

Second to explain the output. Before you swap you basically have d pointing to a string containing "hellohai" and e pointing to a string containing "asd". After the swap f and e point to a string containing "hellohai" and d points to a string containing "asd". You then modifying the string that f and e are pointing to through f so the now that is "1ellohai". You then print everything, and the output is as expected.

Memory allocated by malloc is writable. What you are probably confusing this with is the following:

char *f = "hello";
f[0] = '1';

This is a bad idea and leads to undefined behavior.

Finally, as a caveat in C it is generally not a good idea to cast the result of malloc.

Community
  • 1
  • 1
missimer
  • 4,022
  • 1
  • 19
  • 33
0
    d=(char*)malloc(10);   //buffer for 10 chars 
    e=(char*)malloc(5);    //buffer for 5 chars 

These are not size of pointers d and e(You should see their size using sizeof operator.).

The only thing that change is that what these points to . These

    f=d;
    d=e;   
    e=f;

actually don't copy string's . This just changes to what the pointers point. f[0]='1'; // This is correct and is re-writable . Don't confuse it with string literal

For some safety -

1.Don't cast result of malloc.

2.These scanf's shoud be -

    scanf("%9s",d);
    scanf("%4s",e);

as to prevent case when you enter chars more that 9 or 4 which will casue UB

3.free the memory you allocate .

ameyCU
  • 16,489
  • 2
  • 26
  • 41
0

What is happening is that you're mallocing two memory blocks. Those blocks have address, which d and e holds. To confirm that, put these after your scanfs.

printf ("Address of d: %p\n", &d);
printf ("Address of e: %p\n", &e);
printf ("Address of block d(value of d): %p\n", d);
printf ("Address of block e(value of e): %p\n", e);

My output is:

Address of d: 0x7fff037a5488
Address of e: 0x7fff037a5490
Address of block d(value of d): 0xa8e010
Address of block e(value of e): 0xa8e030

Now, when you make the swap between the pointers, all you're doing is changing the memory block references, not the actual pointer address (which you can't do).

You can confirm that by putting those printf after the swaps, like this:

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

int main()
{
        char *d,*e,*f;


        d=(char*)malloc(10);
        e=(char*)malloc(5);

        scanf("%s",d);
        scanf("%s",e);


    printf ("Address of d: %p\n", &d);
    printf ("Address of e: %p\n", &e);
    printf ("Address of f: %p\n", &f);
    printf ("Address of block d(value of d): %p\n", d);
    printf ("Address of block e(value of e): %p\n", e);

        f=d;
        d=e;   
        e=f; //while printing e it prints the whole value contained in f (i.e.1ellohai). How? size of e is 5 only

    printf ("Address of d: %p\n", &d);
    printf ("Address of e: %p\n", &e);
    printf ("Address of f: %p\n", &f);
    printf ("Address of block d(value of d): %p\n", d);
    printf ("Address of block e(value of e): %p\n", e);
    printf ("Address of block f(value of f): %p\n", f);

        f[0]='1'; // f is in read-only memory. So this should fail?
        printf("%s \t %s \t %s \n",d,e,f);


        return 0;
}

And the output:

$ ./draft
hellohai
asd
Address of d: 0x7ffebae87d78
Address of e: 0x7ffebae87d80
Address of f: 0x7ffebae87d88
Address of block d(value of d): 0x2143010
Address of block e(value of e): 0x2143030
Address of d: 0x7ffebae87d78
Address of e: 0x7ffebae87d80
Address of f: 0x7ffebae87d88
Address of block d(value of d): 0x2143030
Address of block e(value of e): 0x2143010
Address of block f(value of f): 0x2143010
asd      1ellohai    1ellohai 

From this you can see that:

    1. The addresses of the pointers never changed.
    1. The references (their values) changed. They got swaped.
    1. e and f point to the same memory block. That's why doing f[0]='1' changes the value printed by both.


A primitive memory layout


After you declare your variables, you memory will look like this:

Values     : | - | - | - |   |   |   | 
Variable   : | d | e | f |   |   |   | 
Memory(hex): | 1 | 2 | 3 | 4 | 5 | 6 |

When you malloc, your computer gives d the block at address 5 and e the block at address 6, so now it looks like this:

Values     : | 5 | 6 | - |   |   |   | 
Variable   : | d | e | f |   |   |   | 
Memory(hex): | 1 | 2 | 3 | 4 | 5 | 6 |

After you read your strings, the contents of the blocks at 5 and 6 will get written:

Values     : | 5 | 6 | - |   | hellohai | asd | 
Variable   : | d | e | f |   |          |     | 
Memory(hex): | 1 | 2 | 3 | 4 |    5     |  6  |

When you print d, it access the memory address it points to (5 in this case) and print the contents. Same for the e variable.

Now, when you swap the values doing:

f=d;

Values     : | 5 | 6 | 5 |   | hellohai | asd | 
Variable   : | d | e | f |   |          |     | 
Memory(hex): | 1 | 2 | 3 | 4 |    5     |  6  |

d=e;

Values     : | 6 | 6 | 5 |   | hellohai | asd | 
Variable   : | d | e | f |   |          |     | 
Memory(hex): | 1 | 2 | 3 | 4 |    5     |  6  |

e=f;

Values     : | 6 | 5 | 5 |   | hellohai | asd | 
Variable   : | d | e | f |   |          |     | 
Memory(hex): | 1 | 2 | 3 | 4 |    5     |  6  |

Now e and f point to the same place (where d used to point) and d points to where e used to point. It's important to note that the actual values of the addresses 5 and 6 never got touched.

And when you do:

f[0]='1';

You're telling the computer to access the first byte of the contents of the memory block at address 5 and change it. So now you have:

Values     : | 6 | 5 | 5 |   | 1ellohai | asd | 
Variable   : | d | e | f |   |          |     | 
Memory(hex): | 1 | 2 | 3 | 4 |    5     |  6  |

This is a very simple representation of what you memory might look like so you can get the idea of how it works.

Community
  • 1
  • 1
Enzo Ferber
  • 3,029
  • 1
  • 14
  • 24