我对指针感到困惑。这是交换两个名称的代码。请参阅代码。考虑输入: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"
的字符串。 交换后,f
和e
指向包含"hellohai"
的字符串,d
指向包含"asd"
的字符串。 然后修改f
和e
通过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
这些不是指针的大小d
和e
(您应该使用运算符查看它们的大小sizeof
(。
唯一改变的是这些指向什么.这些
f=d;
d=e;
e=f;
实际上不要复制字符串的.这只是更改为指针指向的内容。 f[0]='1'; 这是正确的,并且可以重写。不要将其与字符串文字混淆
为了安全起见——
1.不要投malloc
结果。
2.这些scanf
应该是——
scanf("%9s",d);
scanf("%4s",e);
为了防止当您输入字符超过9
或4
会导致 UB
3. free
您分配的内存。
正在发生的事情是你正在malloc
两个内存块。这些块具有地址,d
和e
都持有该地址。要确认这一点,请将这些放在您的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
由此可见:
- 指针的地址从未更改。
- 引用(其值(已更改。他们被交换了。
-
e
和f
指向同一内存块。这就是为什么做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 |
读取字符串后,将写入 5 和 6 处的块的内容:
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 |
现在,e
和f
指向同一个地方(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 |
这是您的记忆可能看起来像什么的非常简单的表示,因此您可以了解它是如何工作的。