简体   繁体   English

使用非 malloced 指针变量交换名称(malloced 的)

[英]Swapping names(malloced ones) using non malloced pointer variable

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).考虑输入:hellohai(for d) 和 asd(for e)。 Output i am getting : asd 1ellohai 1ellohai我得到的输出: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;
}

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. d指向一个 10 字节的缓冲区,而e指向一个 5 字节的缓冲区。

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.它更改 10 字节缓冲区的第一个字节。 f is not read-only because it is pointing to the same malloc'ed buffer that d originally (and now e ) pointed to. f不是只读的,因为它指向d最初(现在是e )指向的同一个 malloc 缓冲区。

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 . f具有d的旧值,并指向通过malloc分配的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" .在你交换之前,你基本上有d指向一个包含"hellohai"的字符串和e指向一个包含"asd"的字符串。 After the swap f and e point to a string containing "hellohai" and d points to a string containing "asd" .交换后fe指向包含"hellohai"的字符串, d指向包含"asd"的字符串。 You then modifying the string that f and e are pointing to through f so the now that is "1ellohai" .然后修改fe通过f指向的字符串,所以现在是"1ellohai" You then print everything, and the output is as expected.然后打印所有内容,输出符合预期。

Memory allocated by malloc is writable. malloc分配的malloc是可写的。 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 .最后,作为 C 中的一个警告malloc的结果通常不是一个好主意

    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.).这些不是指针de的大小(您应该使用sizeof运算符查看它们的大小。)。

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'; 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 . 1.不要转换malloc结果。

2.These scanf 's shoud be - 2.这些scanf应该是 -

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

as to prevent case when you enter chars more that 9 or 4 which will casue UB为了防止输入超过94字符时出现UB 的情况

3. free the memory you allocate . 3. free你分配的内存。

What is happening is that you're malloc ing two memory blocks.发生的事情是您正在malloc两个内存块。 Those blocks have address, which d and e holds.这些块有地址, de持有。 To confirm that, put these after your scanf s.要确认这一点,请将它们放在您的scanf之后。

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:您可以通过将这些printf放在交换之后来确认,如下所示:

#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. ef指向同一个内存块。 That's why doing f[0]='1' changes the value printed by both.这就是为什么f[0]='1'改变两者打印的值。


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:当你 malloc 时,你的计算机给了d地址5的块和e地址6的块,所以现在它看起来像这样:

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:读取字符串后,将写入56块的内容

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.当您打印d ,它会访问它指向的内存地址(在本例中为5 )并打印内容。 Same for the e variable. e变量相同。

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.现在ef指向同一个地方( d曾经指向的地方), d指向e曾经指向的地方。 It's important to note that the actual values of the addresses 5 and 6 never got touched .重要的是要注意地址56的实际从未被触及

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.您告诉计算机访问地址5处内存块内容的第一个字节并更改它。 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.这是一个非常简单的表示您的内存可能是什么样子的,因此您可以了解它是如何工作的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM