#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int *ptr1, *ptr2, *ptr3;
ptr1 = urn; //把一个地址赋给指针
ptr2 = &urn[2]; //把一个地址赋给指针
//解引用指针,以及获得指针的地址
printf("pointer value,dereferenced pointer, pointer address: \n");
printf("ptr1 = %p, *ptr1 = %d,&ptr1 = %p\n", ptr1, *ptr1, &ptr1);
//指针加法
printf("\nadding an int to apointer?:\n");
printf("ptr1 + 4 = %p, *(ptr1 + 4)= %d\n", ptr1 + 4, *(ptr1 + 4));
ptr1++; //递增指针
printf("\nvalues afterptr1++:\n");
printf("ptr1 = %p, *ptr1 = %d,&ptr1 = %p\n", ptr1, *ptr1, &ptr1);
ptr2--; //递减指针
printf("\bvalues after--ptr2:\n");
printf("ptr2 = %p, *ptr2 = %d,&ptr2 = %p\n", ptr2, *ptr2, &ptr2);
--ptr1; //恢复为初始值
++ptr2; //恢复为初始值
printf("\nPointers reset tooriginal values:\n");
printf("ptr1 = %p, ptr2 =%p\n", ptr1, ptr2);
//一个指针减去另一个指针
printf("\nsubtracting one pointerfrom anoter: \n");
printf("ptr2 = %p, ptr1 = %p, ptr2- ptr1 = %d\n", ptr2, ptr1, ptr2 - ptr1);
//一个指针减去一个整数
printf("\nsubtracting an int froma pointer:\n");
printf("ptr3 = %p, ptr3 - 2 =%p\n", ptr3, ptr3 - 2);
return 0;
}
/*
赋值:可以把地址赋给指针,地址要和指针类型兼容。
可以使用数组名、带地址运算符(&)的变量名、另一个指针进行赋值。
解引用: *运算符给出指针指向地址上储存的值。*ptr1的初值是100,该值储存在编号为00BEFCB0的地址上。
取址:和所有变量一样,指针变量也有自己的地址和值。对指针而言,&运算符给出指针本身的地址。
本例中,ptr1 储存在内存编号为00BEFCA4的地址上,该存储单元储存的内容是00BEFCB0,即urn的地址。因此&ptr1是指向ptr1的指针,而ptr1是指向utn[0]的指针。
指针与整数相加:可以使用+运算符把指针与整数相加,或整数与指针相加。无论哪种情况,整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。
递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素。
指针减去一个整数:可以使用-运算符从一个指针中减去一个整数。
递减指针:当然,除了递增指针还可以递减指针。
指针求差:可以计算两个指针的差值。通常,求差的两个指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。差值的单位与数组类型的单位相同。
比较:使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。
注意:减法有两种。可以用一个指针减去另一个指针得到一个整数,或者用一个指针减去一个整数得到另一个指针。
一定要牢记一点:千万不要解引用未初始化的指针。例如,考虑下面的例子:
int * pt; // 未初始化的指针
*pt = 5; // 严重的错误
切记:创建一个指针时,系统只分配了储存指针本身的内存,并未分配储存数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。
C 程序员创建了指针数组、函数指针、指向指针的指针数组、指向函数的指针数组等。
保护数组中的数据:
处理基本类型(如,int)的函数时,要选择是传递int类型的值还是传递指向int的指针。
通常都是直接传递数值,只有程序需要在函数中改变该数值时,才会传递指针。
对于数组别无选择,必须传递指针,因为这样做效率高。
如果一个函数按值传递数组,则必须分配足够的空间来储存原数组的副本,然后把原数组所有的数据拷贝至新的数组中。
如果把数组的地址传递给函数,让函数直接处理原数组则效率要高。
传递地址会导致一些问题。
C 通常都按值传递数据,因为这样做可以保证数据的完整性。
*/
#include<stdio.h>
#defineSIZE 5
void show_array(const double ar[], int n);
void mult_array(double ar[], int n, double mult);
intmain(void)
{
double dip[SIZE] = { 20.0, 17.66, 8.2,15.3, 22.22 };
printf("The original diparray:\n");
show_array(dip, SIZE);
mult_array(dip, SIZE, 2.5);
printf("The dip array aftercalling mult_array():\n");
show_array(dip, SIZE);
return 0;
}
/*-- 显示数组内容 --*/
voidshow_array(const double ar[], int n)
{
int i;
for (i = 0; i < n; i++)
printf("%8.3f ", ar[i]);
putchar('\n');
}
/*-- 把数组的每个元素都乘以相同的值 --*/
voidmult_array(double ar[], int n, double mult)
{
int i;
for (i = 0; i < n; i++)
ar[i] *= mult;
}
/*
const不是要求原数组是常量,而是该函数在处理数组时将其视为常量,不可更改。
使用const可以保护数组的数据不被修改,就像按值传递可以保护基本数据类型不被改变一样。
指向const的指针不能用于改变值。
double rates[5] = {88.99, 100.12, 59.45, 183.11, 340.5};
const double * pd = rates; // pd指向数组的首元素
第2行代码把pd指向的double类型的值声明为const,这表明不能使用pd来更改它所指向的值:
*pd = 29.89; // 不允许
pd[2] = 222.22; //不允许
rates[0] = 99.99; // 允许,因为rates未被const限定
int sum(int * ar, int n) //通用方法
{
int i;
int total = 0;
for(i = 0; i < n;i++) //使用N个元素
total +=ar[i];
return total;
}
第一个形参告诉函数该数组的地址个数据类型;第二个形参告诉函数该数组中元素的个数。
注意:只有在函数原型或函数定义头中,才可以用int ar[]代替int * ar。
int sum(int ar[], int n);
int *ar形式和int ar[]形式都表示ar是一个指向int的指针。
区别:int ar[]只能用于声明形式参数。
int ar[]表明指针ar指向的不仅仅是一个int类型的值,还有int类型数组的元素。
下面四种原型是等价的:
int sum(int *ar, intn);
int sum(int *, int);
int sum(int ar[],int n);
int sum(int [],int);
在函数定义中不能省略参数名。下面两种形式的函数定义等价:
int sum(int *ar, intn);
{
......
}
int sum(int ar[],int n)
{
......
}
可以使用以上任意一种函数原型和函数定义。
*/
#include<stdio.h>
int main(void)
{
int zippo[4][2] = { { 2, 4 }, { 6, 8 },{ 1, 3 }, { 5, 7 } };
printf(" zippo = %p, zippo + 1 = %p\n", zippo,zippo + 1);
printf("zippo[0] = %p, zippo[0] +1 = %p\n", zippo[0], zippo[0] + 1);
printf("zipp0[0][0] = %d\n",zippo[0][0]);
printf(" *zippo[0] = %d\n",*zippo[0]);
printf(" **zippo = %d\n",**zippo);
printf(" zippo[2][1] = %d\n", zippo[2][1]);
printf("*(*(zippo + 2) + 1) =%d\n", *(*(zippo + 2) + 1));
return 0;
}
/*
二维数组zippo的地址和一维数组zippo[0]的地址相同。它们的地址都是各自数组首元素的地址,因而与&zippo[0][0]的值也相同。
差别:zippo[0]指向一个4字节的数据对象。zippo[0]加1,其值加4。数组名zippo 是一个内含2个int类型值的数组的地址,所以zippo指向一个8字节的数据对象。因此,zippo加1,它所指向的地址加8字节。
zippo[0]和*zippo完全相同。对二维数组名解引用两次,得到储存在数组中的值。使用两个间接运算符(*)或者使用两对方括号([])都能获得该值,还可以使用一个*和一对[]这种方法来实现。
注意:与 zippo[2][1]等价的指针表示法是*(*(zippo+2) + 1)。
zippo 二维数组首元素地址(每个元素都是内含两个int类型元素的以为数组)
zippo + 2 二维数组的第三个元素(即一维数组)的地址。
*(zippo + 2) 二维数组的第三个元素(即一维数组)的首元素(一个int类型的值)地址。
*(zippo + 2) + 1 二维数组的第三个元素(即一维数组)的第二个元素(一个int类型的值)地址。
*(*(zippo + 2) + 1) 二维数组的第三个一维数组的第2个int类型元素的值,即数组的第三行第二列的值(zippo[2][1])。
*/
规则说明:
A.从变量名称开始;
char **argv;
int (*daytab)[13];
int *daytab[13];
void *comp();
void (*comp)();
char (* (*x())[])();
char (*(*x[3])())[5];