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

Swapping names(malloced ones) using non malloced pointer variable

我对指针感到困惑。这是交换两个名字的代码。请看代码。考虑输入:hellohai(for d) 和 asd(for e)。 我得到的输出: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;
}

当你这样做时:

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

d 指向 10 字节缓冲区,e 指向 5 字节缓冲区。

那么你有这个:

    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

您实际上并没有将字符串从一个复制到另一个。你真的在改变指针。

那么当你这样做的时候:

f[0]='1';

它改变了10字节缓冲区的第一个字节。 f 不是只读的,因为它指向与 d 最初(现在 e)指向的同一个 malloc 缓冲区。

交换指针时,交换的是指针变量中的内存位置。 f 具有 d 的旧值,并指向通过 malloc 分配的内存。因此

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

不正确。

二来解释输出。在交换之前,基本上 d 指向包含 "hellohai" 的字符串,e 指向包含 "asd" 的字符串。交换后 fe 指向包含 "hellohai" 的字符串,而 d 指向包含 "asd" 的字符串。然后修改 fe 通过 f 指向的字符串,所以现在是 "1ellohai"。然后打印所有内容,输出符合预期。

malloc分配的内存是可写的。您可能将其与以下内容混淆:

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

这是个坏主意,会导致未定义的行为。

最后,作为 C 中的警告 it is generally not a good idea to cast the result of malloc

    d=(char*)malloc(10);   //buffer for 10 chars 
    e=(char*)malloc(5);    //buffer for 5 chars 

这些不是指针 de 的大小(您应该使用 sizeof 运算符查看它们的大小。)。

唯一改变的是这些指向的内容。这些

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

实际上不要复制字符串的 .这只是改变了指针指向的内容。 f[0]='1'; // 这是正确的并且是可重写的。不要将它与字符串文字混淆

为了安全起见-

1.Don未投出 malloc 的结果。

2.These scanf的应该是-

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

为了防止输入的字符多于 94 会导致 UB

3.free你分配的内存。

正在发生的事情是您 mallocing 了两个内存块。这些块有地址,de 持有。为确认这一点,请将这些放在 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);

我的输出是:

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

现在,当您在指针之间进行交换时,您所做的只是更改 内存块引用 ,而不是实际的指针地址(您 做不到).

您可以通过将 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;
}

并且输出:

$ ./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 

由此可见:

    1. 指针的地址从未改变。
    1. 引用(它们的值)改变了。他们被交换了。
    1. ef指向同一个内存块。这就是为什么 f[0]='1' 会改变两者打印的值。


原始内存布局


声明变量后,您的内存将如下所示:

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

当你 malloc 时,你的计算机给 d 地址 5 的块和 e 地址 6[= 的块101=],所以现在看起来像这样:

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

读取字符串后,56 块的 内容 将被写入:

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

当你打印d时,它会访问它指向的内存地址(在本例中为5)并打印内容。 e 变量也是如此。

现在,当您交换值时:

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  |

现在ef指向同一个地方(其中d用于点)和d点到e习惯的地方。 重要的是要注意地址56的实际永远不会感动了.

当你这样做时:

f[0]='1';

您是在告诉计算机访问地址 5 处内存块内容的第一个字节并更改它。所以现在你有:

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

这是您的记忆可能看起来的一个非常简单的表示,因此您可以了解它是如何工作的。