您的位置:首页 > 其它

【指针专场】这次一定啃透你哼

2016-03-08 00:31 274 查看
1、在C中,对一个指针加1的结果是对该指针【增加一个存储单元(storage unit)】,对于数组而言,地址会增加到【下一个元素的地址】,而不是下一个字节。

2、Q:为什么声明指针时必须声明它所指向的对象的类型?

       A:计算机需要知道存储对象所用的字节数,所以只有地址信息是不够的,还需知道一个存储单元的大小(即指向的对象的字节大小),从而得到下一个元素的地址。

     注意,即使指针时指向标量的,也需要声明指针类型,否则*pt操作不能正确返回数值。

3、关于指针定义的几个Tips:

(1)【指针的数值】就是它所【指向的对象的地址】。对于包含多个字节的数据类型,比如double类型的变量,对象的地址通常指的是其【首字节】的地址。

(2)在指针前运用运算符*就可以得到该指针【所指对象的数值】。

(3)对指针加1,等价于对【指针的值】加上它【指向的对象的字节大小】。

4、数组与指针间的关系:

首先理解两个等式:

dates + 2 == &dates[2]; /*地址的比较,两者相同*/
*(dates + 2) == dates[2]; /*值的比较,两者相同*/

即总结下来就是:可以用指针标识数组的每个元素,并得到每个元素的数值。

从本质上来说,对同一个对象有两种不同的符号表示方法,C语言标准在描述数组时,确实借助了指针的概念。例如,定义ar
时,意思是*(ar+n),即“寻址到内存中的ar,再移动n个单位,再取出数值。”

5、区分*(dates + 2) 和*dates + 2。

【间接运算符*的优先级高于+】,故*dates + 2等价于(*dates) + 2。则两者的意义分别为:

*(dates + 2) /*dates[2],即dates第三个元素的值*/

*dates + 2 /dates[0]+2,即dates第一个元素的值加2的和*/

6、声明数组参量

由于数组名就是数组首元素的地址,所以如果【实际参数是一个数组名】,那么形式参量必须是与之相匹配的指针。注意以下四种原型都是等价的:

int sum(int *ar, int n);

int sum(int ar[], int n);
int sum(int *, int n);
int sum(int [], int ); /*C中原型允许省略名称*/
7、向函数传递数组信息的另一种方法

传递两个参数:第一个参数指明数组的起始地址,第二个参数指明数组的结束地址。如:

int sum(int *start, int *end);

在遍历数组中的每个元素时,可以直接修改指针本身,使指针依次指向各个数组元素,这利用了指针参数是变量的事实。如:

while(start < end) {
total += *start;
start ++;
}

因为这是一个对于不相等关系的判断,所以end实际指向的位置是在数组的最后一个元素之后。C保证在为数组分配存储空间时,指向数组之后的第一个位置的指针也是合法的。请注意使用这种越界指针可是函数调用的形式更简洁

ans = sum(arr, arr+SIZE);

而上面的循环体也可精简为一行代码:

total += *start++;

【一元运算符*和++具有相等的优先级】,但它在结合时是【从右向左】进行的。这意味着++应用于start而不是(*start)。也就是说,是指针自增1,而不是指针指向的数据自增1。上述代码表示先把指针指向的数据加到total上,然后指针再自增1。(注意,尽管这样表示正确,但为清晰起见,应该使用*(start++))

若代码改为total += *++start; 则顺序变为指针先自增1,然后再使用新地址其指向的值加到total上。

若代码为:total += (*start)++;
则会使用start指向的数据,然后再使该数据自增1,而不是指针自增1。这样指针的地址永远不变,但其中的元素改变了。这样会使程序陷入死循环。

8、指针操作(重要!)

① 赋值:可以把一个地址赋值给指针。通常使用数组名或地址运算符&来进行地址赋值。

int urn[5] = {100,200,300,400,500};
int *ptr1, *ptr2;

ptr1 = urn; //把一个地址赋给指针
ptr2 = &urn[2]; //把一个地址赋给指针

printf("pValue,  drpointer,  paddress\n");
printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);
printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n", ptr2, *ptr2, &ptr2);




上述代码中,把数组urn的起始地址赋给ptr1,该地址是编号0x0029FEEC的内存单元。变量ptr2得到的是数组第三个也即urn[2]的地址。

注意:地址应该与指针类型兼容,即,不能把一个double类型的地址赋给一个指向int的指针。

②求值或取值: 运算符*可取出指针指向地址中存储的数值

故*ptr1输出为100,即存储在地址0x0029FEEC中的值。

③取指针地址:指针与其他变量一样具有地址和数值,使用&运算符可以得到存储指针本身的地址

本例中,ptr1存储在内存地址0x0029FEE8中,该内存单元的内容是0x0029FEEC,即urn的地址。

ptr3 = ptr1+4;
printf("\nadding an int to a pointer:\n");
printf("ptr1 + 4 = %p, *(ptr1 + 4) = %d\n", ptr1+4, *(ptr1+4));
ptr1++;
printf("\nvalues after ptr1++\n");
printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);
ptr2--;
printf("\nvalues after ptr2--\n");
printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n", ptr1, *ptr1, &ptr1);
ptr1--;
ptr2++;
printf("\nPointers reset to original values:\n");
printf("ptr1 = %p, ptr2 = %p", ptr1, ptr2);

printf("\nsubtracting one pointer from another:\n");
printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);

printf("\nptr2 - ptr1 = %d\n", ptr2 - ptr1);

printf("\nsubtracting one int from a pointer:\n");
printf("ptr3 = %p, ptr3 - 2 = %p\n", ptr3, ptr3-2);




④将一个整数加给指针:可以用+运算符讲一个整数加给指针,或者把一个指针加给一个整数。

两种情况下,这个【整数】都会和【指针所指字节类型的字节数】相乘,然后所得的结果会【加到初始地址】上。于是,ptr+4的结果等同于&urm[4]。

注意:如果相加的结果超出了初始指针所指向的数组的范围,那么这个结果是【不确定】的,除非【超出数组最后一个元素的地址是确保有效】的。

⑤增加指针的值:可以通过一般的加法和增量运算符来增加一个指针的值。

对指向某数组元素额指针做增量运算,可以让指针【指向】该数组的下一个元素。因此,ptr1++运算把ptr1加上数值4,使ptr1指向urn[1],现在ptr1的值是0x0029FEEC(urn[1]元素的地址),*ptr1的数值为200(urn[1]的值),注意:ptr1本身的地址仍是0x0029FEE8。变量不会因为它存储的值的变化而移动位置。

⑥从指针中减去一个整数:可以用-运算符从一个指针中减去一个整数。指针必须是第一个操作数,或者是一个指向整数的指针。

⑦减小指针的值:指针当然也可以做减量运算。

⑧求差值:可以求两个指针间的差值。

通常对分别指向同一个数组内两个元素的指针求差值,以求出元素之间的距离。差值的单位是相应类型的大小。如本例中,ptr2-ptr1的值是2,表示【指针所指向对象之间的距离为2个int数值大小】,而不是两个字节。

有效指针差值运算的前提是参加运算的两个指针是指向同一个数组,指向两个不同数组的指针之间的差值运算可能会得到一个数值结果,但也可能导致一个运行时错误。

⑨可以使用关系运算符来比较两个指针的值,前提是两个指针具有相同的类型。

9、特别注意:看这里看这里~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: