关于指针的疑惑

49 篇文章 0 订阅
 

 指针具有方便性,可以实现程序的高效执行,但是有一些疑惑。

有时候弄明白了,但是总忘,所以记录下来,以备查看。

有些不足的地方,以后想起来再进行补充。

凡是用到指针的地方,画个图出来!(经验总结)

1. 指针之间“=”赋值

用“=”赋值时,两个指针指向同一块地址空间。因此,下面的程序执行会提示出错,因为地址空间被释放了,即所谓的野指针

int main()
{
    char * p1=new char[32];
    memset(p1, 0, 32);
    strcpy(p1, "I love china");
    char * p2=p1;
    printf("p1 point to %p, p2 point to %p\n", p1, p2);
    delete(p1);
    printf("%s\n", p2);
}
运行结果如下:

p1 point to 0x8f2a008, p2 point to 0x8f2a008


即,这边没有输出p2所指的字符串

2. 给函数传指针时,最好指明所传数据的长度,便于函数进行取值。如果出现类型不一致时,直接用内存复制函数memcpy() 来实现相互转换。

例如:

int nGroupID;
char * cGroupID;
memcpy(cGroupID, &nGroupID, sizeof(int));

3. 关于char和string类型。个人感觉,string等同于char *,而且在windows中的CString也等同于LPCTSTR,更加深了这种想法。

所以,在使用char * 时,跟使用string相似。

void main()
{
	char * p1="hello, world";
	char * p2=p1; 
	printf("%s\n", p2);
}


4. 指针长度固定为4个字节(32位操作系统下)

void main()
{
	char * p1="hello, world";
	char * p2=p1; 
	printf("%d\n", sizeof(p2));
	printf("%d\n", sizeof(*p2));
}


因此,作参数时,要注明该指针所指地址中的数据是有用的。

下面是一个示例:

#include <stdio.h>
#include <string.h>

char * add(char * x, int xlen, char * y, int ylen)
{
	int len=xlen+ylen;
	char * result=new char[len];
	memset(result, 0, len);
	memcpy(result, x, xlen);
	memcpy(result+xlen, y, ylen);

	return result;
}

void main()
{
	char * p1="hello, world";
	char * p2="i am byh";
	char * p3=add(p1, sizeof("hello, world")-1, p2, sizeof("i am byh"));
	printf("%s\n", p3);
}

 5. 取指针内容。用*取指针时,所指向的仅仅是指针声明的类型所占内存空间中的第一个,而之后的并不会取到。

如下例子:

void main()
{
	char * p1="hello, world";
	char * p2= new char;
	(*p2)=(*p1);
	printf("%s\n", p2);

}


输出内容为:h葺葺葺葺葺?

即,只有第一个是有效的。

6. 指针的智能性。

在声明一个指针类型时,系统就为该指针所指向的空间分配好了该类型应该占用的空间。

用指针作为传出参数的例子:

void CGroupSockPool::getSock(int ID, SOCKET * pSock)
{
	int pos=getGroupPos(ID);
	if(pos>=m_nCurrentNum)
	{
		printf("没有找到对应的组\n");
		pSock=NULL;
		return;
	}

	(*pSock)=pool[pos]->sock;
}

7. 指针作为参数时,函数会复制指针

在所有的函数传参中,只有引用不会复制参数。对于这个问题之前一直有误解,直到昨天碰到问题的时候,请教同学才知道。(不是科班出身真是坑爹呀)

在传递指针给函数时,函数内部会分配指针(复制实参),指向与实参相同的地址空间。因此,对形参的操作只会改变内存所指向地址的内容实参所指向的地址是不会发生变化的

示例代码如下:

#include <stdio.h>

void swap(int * p1, int * p2)
{
	int * temp=p1;
	p1=p2;
	p2=temp;
	printf("in swap: (*p1)=%d, (*p2)=%d\n", *p1, *p2);
	printf("in swap: address of p1 and p2: %p, %p\n", p1, p2);	
}

void main()
{
	int * a=new int;
	int * b=new int;
	(*a)=3;
	(*b)=5;
	printf("before swap: (*a)=%d, (*b)=%d\n", *a, *b);
	printf("before swap: address of a and b: %p, %p\n", a, b);
	swap(a, b);
	printf("after swap: (*a)=%d, (*b)=%d\n", *a, *b);
	printf("after swap: address of a and b: %p, %p\n", a, b);
}
输出结果如下:

before swap: (*a)=3, (*b)=5
before swap: address of a and b: 00370FE0, 00371018
in swap: (*p1)=5, (*p2)=3
in swap: address of p1 and p2: 00371018, 00370FE0
after swap: (*a)=3, (*b)=5
after swap: address of a and b: 00370FE0, 00371018

分析:

可以看到,尽管在swap()函数中,将指针p1和指针p2的所指内存进行了交换,但实际上复制了两个指针,并分别指向a和b指向的内存空间。在函数调用之后,复制的指针生命周期结束后销毁,对实参并没有影响!


8. 二级指针

有时候会用二级指针来存储一些数据。给该二级指针用new动态分配一个连续空间,然后用数组下标进行访问。

出错状况:在执行删除操作时,比较习惯用内存操作函数memcpy()直接用后面的内容把前面的内容覆盖掉,以达到删除的目标。

原因:用下标进行访问时,访问的是二级指针连续空间中的指针还是该指针指向的内容?经过试验,得出的结论是后者,即指针指向的内容。


定义了结构体:

typedef struct _Student
{
	char name[16];
	int ID;
}Student, * pStudent;

在实验中试了两种覆盖方法:

(1) memcpy(pStu+1, pStu+2, 3*sizeof(pStudent));

(2) memcpy(pStu[1], pStu[2], 3*sizeof(Student));

在用第二种方法时,会出现错误的结果,应该是为一级指针所指向的内存分配的空间不连续导致的;所以用一级指针来做删除会更可靠!

注意:用数组下标去访问时,访问得到的是一级指针所指向的内存空间,而非一级指针本身

总结:

1. 给函数传参时,除非明确指针所指内容的长度,否则一定要把指针所指内容的长度也作为参数传递过去。

2. 内存操作函数memset(), memcpy()包含在头文件#include <string.h>中,很有用。因为可以作为不同类型的转换手段。

注意:不同类型的数值表达方式不相同,所以内存所指的空间内容虽然相同,但表达出来可能就会有问题。

示例:

void main()
{
	int ID=1234;
	char cID[sizeof(int)]={0};
	memcpy(cID, &ID, sizeof(int));
	
	int ID2;
	memcpy(&ID2, cID, sizeof(int));
	printf("%p\n", *cID);
	printf("%d\n", ID2);
}
输出结果:

-46

1234

分析原因:

1234在内存中表达为:(小端 表示 , 以字节为单位,内存中左低右高)0xd2 0x04 0x00 0x00

cID所指的字节:0Xd2, 二进制表示:1101  0010  

首位为1,故取反,加一:0010 1110, 即-46

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值