main()
{
int i;
int *p = &i;
printf("%d",sizeof(p));
}
我32位CPU,
在VC测试: 4
在TC测试: 2
请问,指针变量存储单元的大小与什么有关?
指针大小和当前系统的地址总线位数一样,TC运行在16位模拟器中,所以指针大小是16位即2个字节,vc就是32位的,int类型的大小也和这个一样是变的,其它类型的大小不会变的
TC和VC所支持的语言标准不同,跟16位和32位编程无关。
TC支持纯C语言,纯C语言里的6种int型数据中只有long和unsigned
long型长度是4字节,另外4种长度是2字节,而VC里支持的C语言全部6种int型数据长度全部是4字节。我们知道,指针的长度和其相应的数据类型长
度相等,所以int型指针在TC里是2字节,在VC里是4字节。
指针的大小是问:一个指针变量占用多少内存空间?
分析:既然指针只是要存储另一个变量的地址,。注意,是存放一变量的地址,而不是存放一个变量本身,所以,不管指针指向什么类型的变量,它的大小总是固定的:只要能放得下一个地址就行!(这是一间只有烟盒大小的“房间”,因为它只需要入一张与着地址的纸条)。
存放一个地址需要几个字节?答案是和一个 int 类型的大小相同:4字节。
所以,若有:
int* pInt;
char* pChar;
bool* pBool;
float* pFloat;
double* pDouble;
则:sizeof(pInt)、sizeof(pChar)、sizeof(pBool)、sizeof(pFloat)、sizeof(pDouble)的值全部为:4。
(你敢拆电脑吗?拆开电脑,认得硬盘数据线吗?仔细数数那扁宽的数据线由几条细线组成?答案:32条,正是 4 * 8)。
指向数组的指针
现在,来说说指针指向一个数组的情况。
int arr[]
= {1,2,3,4,5}; //一个数组
int* parr; //一个指针。
parr = arr; //没有‘&’?对啊,对数组就是不用取址符。
cout << *parr << endl;
//输出 *parr
先猜想一下,输出结果是什么?
最“直觉”的想法是:parr
指向一个数组,那么输出时,自然是输出数组中的所有元素了。所以答案应该是:“12345”了?
不过,我想,学过前面的数组,我们就能知道这种想法错误。
正确答案是输出数组中的第一个元素: 1 。
接下来,如果是这样输出呢?
parr =
arr;
cout << parr << endl;
答案是输出了arr的地址。就等同于输出
arr 。
cout << arr << endl; 的作用
在这里,难点是要记住,数组变量本身就是地址。所以有:
1、想让指针变量存储一个数组的地址(想让指针变量指向一个数组)时,不用取址符。
2、解析一个指向数组的指针,得到的是数组的第一个元素
偏移指针
int* parr2;
parr2 = parr + 1;
加1后,指针指向了下一个元素。由于这是一个 int
类型的数组,每个元素的大小是4个字节。所以第二个元素的地址是10000014。
重点 &
易错点:对指针 进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。
知到了如何“加”,也就知道了如何“减”。减以后,得到的是上一个元素的大小。
所以,一个类型为 T 的指针的移动,以
sizeof(T) 为移动单位。
所以,一个类型为 T 的指针的移动,以
sizeof(T) 为移动单位。
比如:
int* pInt; 移动单位为
sizeof(int) 。即:4。而 char* pChar; 移动单位为
sizeof(char)。即1。
指针的最小移动单位
int arr[6] = {101,102,103,104,105,106};
int* pI = arr;
cout << "pI
是一个指向整型数组的指针,移动单位:4字节" << endl;
for (int i = 0; i < 6; i++)
cout << "pI + " << i << " ----> " << pI + i << ", *(pI + i) = " << *(pI
+ i) << endl;
cout <<
"------------------------------------" << endl;
//接下
来是一个指向char类型数组的指针:
char str[4] = {'a','b','c','d'}
char* pC = str;
cout << "pC
是一个指向字符数组的指针,移动单位:1字节" << endl;
for (int
i=0; i < 4; i++)
cout << "pC + " << i << " ----> " <<
(int)(pC + i) << ", *(pC + i) = " << *(pC
+ i) << endl;
system("PAUSE");
输出结果:
(指针的最小移动单位)
每一行中,程序先输出指针加上偏移量以后的值(地址),比如:1245024、1245028;然后输出偏移后指针指向的值,比如101,102。
查看移动前后指针存储的地址,我们就可以计算出移动单位。1245028 - 1245024 = 4 (byte)。
* (地址解析符)与 ++ 的优先级
指针的前置++与后置++的区别
//代码片段一:
int arr[] =
{1,2,3,4,5,6,7,8,9,10};
int* parr1 = arr;
int A = *parr1++;
int B =
*parr1;
cout << "A = " << A << endl;
cout << "B = " << B << endl;
输出结果:
A
= 1;
B = 2;
代码片段二:
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int* parr1 = arr;
int A
= *++parr1;
int B = *parr1;
cout << "A = " << A << endl;
cout << "B = " << B << endl;
输出结果:
A
= 2;
B
= 2;
19.8.7* (地址解析符)与 ++ 的优先级
从上例中我们可以看到。当 * (作为地址解析符)和 ++ 同时作用在指针时,不管是前置还是++,都要比*有更高的优先级。比如代码中的:
int A = *parr++;
我们来一个反证:假设*的优先级比++高,那么,应先计算:
*parr 结果为:
1 (第一个元素)
然后计算 1++
,结果为:2。
但实验发现结果为 1,这个1 又是如何来的呢?有点复杂。
首先,++优先计算,所以应先计算:parr++
。
结果是parr指向了下一个元素:2。因为这是后置++,所以,它必须返回自己计算之前的值;所以,在改变parr之前,编译程序会生成一个临时变量,计算原先parr的值。我们假设为
old_parr 。下面是第二步操作:
A = *old_parr。
由于
old_parr 是 parr 原来的值,指向第一个元素,所以
A 得到值: 1 。
可见,后置 ++ 或 后置--
操作,需要系统生成一个临时变量。
如果这个变量占用的内存空间很小(比如指针类型总是只有4字节),则该操作带来的,对程序速度的负面影响可以不计,如果变量很大,并且多次操作。则应在可能的情况下,尽量使用前置++或前置--操作。
你自然会问,前置++就不会产生临时变量吗?我们来试试。
int A = *++parr;
同样,++优先级大于*,所以先计算:++parr。
结果parr
指向下一个元素。因为这是前置++,所以,它只需要返回的,正是自己计算之后的值。下一步是:
A =
*parr;
由于 parr 此时已完成++操作,指向下一个元素。所以 A
得到值: 2。
19.8.8上机实验六:指针的 ++与--操作
int arr [] = {1,2,3,4,5};
int* parr = arr;
//前进
++:
for (int i=0; i < 5; i++) //如果为了优化,你可以写成:
++i :)
{
cout << *parr << endl;
parr++;
//如果为了优化,你可以写成:++parr :D
/*
上面两句你还可以写成一句:
cout << *parr++ <<
endl; //这里,你可不能为了优化写成: *++parr.
*/
}
//后退 --:
for (int i=0; i < 5;
i++)
{
parr--;
cout << *parr << endl;
}
输出结果:
(指针的++与--)