C语言 使用非错误定位指针变量交换名称(错误定位)



我对指针感到困惑。这是交换两个名称的代码。请参阅代码。考虑输入: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具有 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 语言中的警告,投射 malloc 的结果通常不是一个好主意。

当你这样做时:

    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(指向的同一个错误定位缓冲区。

    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您分配的内存。

正在发生的事情是你正在malloc两个内存块。这些块具有地址,de都持有该地址。要确认这一点,请将这些放在您的scanf之后。

printf ("Address of d: %pn", &d);
printf ("Address of e: %pn", &e);
printf ("Address of block d(value of d): %pn", d);
printf ("Address of block e(value of e): %pn", 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: %pn", &d);
    printf ("Address of e: %pn", &e);
    printf ("Address of f: %pn", &f);
    printf ("Address of block d(value of d): %pn", d);
    printf ("Address of block e(value of e): %pn", 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: %pn", &d);
    printf ("Address of e: %pn", &e);
    printf ("Address of f: %pn", &f);
    printf ("Address of block d(value of d): %pn", d);
    printf ("Address of block e(value of e): %pn", e);
    printf ("Address of block f(value of f): %pn", 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 时,您的计算机在地址 5 处给出d块,在地址 6e块,所以现在它看起来像这样:

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过去指向的位置。请务必注意,地址 5 和 6 的实际从未被触及

当您这样做时:

f[0]='1';

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

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

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

相关内容

  • 没有找到相关文章

最新更新