【问题标题】:Swapping names(malloced ones) using non malloced pointer variable使用非分配指针变量交换名称(分配的名称)
【发布时间】:2015-09-11 13:34:21
【问题描述】:

我对指针感到困惑。这是交换两个名称的代码。请看代码。考虑输入: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;
}

【问题讨论】:

  • f[0]只读的。它被分配了d,它指向分配的内存,它总是可写的。
  • 所以你的意思是如果我做类似 f="hello" 的事情,那么只有它是只读的。 e的值呢?
  • f 本身也不是只读的。
  • 问题是什么?
  • e原来指向的东西的大小是5;交换之后,它指向的是大小 10(最初是由 d 指向的)。 ed 本身(指针)的大小不会改变。

标签: c pointers memory malloc dynamic-allocation


【解决方案1】:

当你交换指针时,你交换的是指针变量中的内存位置。 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 中的一个警告。

【讨论】:

    【解决方案2】:

    当你这样做时:

        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'ed 缓冲区。

    【讨论】:

      【解决方案3】:
          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.不要转换malloc的结果。

      2.这些scanf应该是-

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

      为了防止当您输入的字符超过94 时会导致UB

      3.free你分配的内存。

      【讨论】:

        【解决方案4】:

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

        我的输出是:

        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. references(它们的值)发生了变化。他们被交换了。
          1. ef 指向同一个内存块。这就是为什么 f[0]='1' 会改变两者打印的值。


        原始内存布局


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

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

        当你 malloc 时,你的计算机将地址 5 处的块分配给d,并将地址 6 处的块分配给e,所以现在它看起来像这样:

        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  |
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-31
          • 1970-01-01
          • 2011-10-07
          相关资源
          最近更新 更多