1. 指针定义
指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。
\\指针声明:
int *ip; // 整型指针
double *ip; // double 型指针
char *ip; // 字符型指针
2. 指针操作
定义指针;把变量地址赋值给指针;访问指针变量中可用地址的值。
eg:
int var = 20;
int *ip;
ip = &var;
printf("Address of variable: %p\n", &var);
printf("Address stored in ip variable: %p\n", ip); //在指针变量中存储的地址
printf("Value of *ip: %p\n", *ip); //使用指针访问值
Result:
Address of variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip: 20
NULL--空指针
int *ptr = NULL;
printf("ptr 的值是 %p\n", ptr);
ptr 的值是 0
大多数操作系统上,程序不允许访问地址为0 的内存,因为该内存是操作系统保留的。然而,内存地址0有特别重要的意义。它表明该指针不指向一个可访问的内存位置。按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
3. 指针的运算
假设 ptr 为一个指向地址为1000的整型指针,是一个32位的整数,则
ptr++;
执行完上述运算后,ptr指向位置1004,因为ptr每增加一次,它都将指向下一个整数位置,即当前位置往后移4个字节。
若ptr指向一个地址为1000的字符,则该运算会导致指针指向位置1001;
(1) 指针替代数组
· 递增一个指针
const int MAX = 3;
int main()
{
int var[] = {10, 100, 200};
int i; *ptr;
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("存储地址:var[%d] = %x\n", i, ptr);
printf("存储值:var[%d] = %d\n", i, *ptr);
ptr++;
}
return 0;
}
Result:
存储地址:var[0] = bf882b30;
存储值:var[0] = 10;
存储地址:var[1] = bf882b34;
存储值:var[1] = 100;
存储地址:var[2] = bf882b38;
存储值:var[2] = 200;
· 递减一个指针
const int MAX = 3;
int main()
{
int var[] = {10, 100, 200};
int i; *ptr;
ptr = &var[MAX - 1]; //指针中最后一个元素的位置;
for ( i = MAX; i > 0; i--)
{
printf("存储地址:var[%d] = %x\n", i-1, ptr);
printf("存储值:var[%d] = %d\n", i-1, *ptr);
ptr--;
}
return 0;
}
(2) 指针的比较
比较符号可以用 ==; > ; <
const int MAX = 3;
int main()
{
int var[] = {10, 100, 200};
int i; *ptr;
ptr = var;
i = 0;
while( ptr <= &var[MAX - 1])
{
printf("存储地址:var[%d] = %x\n", i, ptr);
printf("存储值:var[%d] = %d\n", i, *ptr);
ptr++;
i++;
}
return 0;
}
3. 函数指针
定义: 指向函数的指针变量。
通常我们所说的指针变量是指向一个整型、字符型或数组等的变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数,传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int); //声明一个指向同样参数、返回值的函数指针类型
int max(int x, int y)
{
return x > y ? x : y;
}
int main(void)
{
int (*p)(int, int) = & max; //&可以省略
int a, b, c, d;
printf("请输入三个数字:");
scanf("%d, %d, %d", &a, &b, &c);
d = p(p( a , b ) , c); //与直接调用等价
printf("最大的数字是: %d\n", d);
return 0;
}
Result:
请输入三个数字:1 2 3
最大的数字是: 3
回调函数
函数指针作为某个函数的参数
函数指针作为某个函数的参数
//回调函数
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i = 0; i<arraySize; i++)
array[i] = getNextValue();
}
//获取随机值
int getNextRandomValue(void)
{
return rand();
}
int main(void)
{
int myarray[10];
populate_array(myarray, 10, getNextRandomValue);
for(int i = 0; i < 10; i++)
{
printf("%d", myarray[i]);
}
printf("\n");
return 0;
}
输出10个随机数。
4. 指向指针的指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针包含实际值的位置。
Pointer(address) → Pointer(address) → Variable(value)
一个指向指针的指针变量必须如下声明,即在变量名前放置两个‘ * ’。例如,下面声明了一个指向int类型指针的指针:
int **var;
当一个目标值被一个指针间接指向另一个指针时,访问这个值需要使用两个星号运算符。
int main()
{
int var;
int *ptr;
int **pptr;
var = 3000;
ptr = &var;
pptr = &ptr;
printf("Value of var = %d\n", var);
printf("Value available at *ptr = %d\n", *ptr);
printf("Value available at **pptr = %d\n", **pptr);
return 0;
}
Result:
Value of var = 3000;
Value available at *ptr = 3000;
Value available at **pptr = 3000;
5. 传递指针给函数
c 语言允许传递指针给函数,只需要简单地声明函数参数为指针类型即可。
下面的实例中,我们传递一个无符号的long型指针给函数,并在函数内改变这个值:
void getSeconds(unsigned long *par);
int main()
{
unsigned long sec;
getSeconds( &sec );
printf("Number of seconds: %d\n", sec );
return 0;
}
void getSeconds(unsigned long *par)
{
*par = time (NULL);
return;
}
Result:
Number of seconds: 1294450468
能接受指针作为参数的函数,也能接受数组作为参数,如下所示:
double getAverage(int *arr, int size);
int main()
{
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
avg = getAverage( balance , 5 );
printf("Average value is :%f\n", avg);
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for ( i = 0; i < size ; i++)
{
sum += arr[i];
}
avg = (double)sum / size;
return avg;
}
Result:
Average value is : 214.40000
对于一维数组来说,数组作为函数参数传递,实际上传递了一个指向数组的指针,在c编译器中,当数组名作为函数参数时,在函数体内数组名自动退化为指针。此时调用函数时,相当于传址,而不是传值,会改变数组元素的值。
对于高维数组来说,可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定 所有维数的大小,也可以省略第一维的大小说明
将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。
6. 从函数返回指针
c语言允许从函数返回指针。为了做到这点,必须声明一个返回指针的函数, 如下所示:
int *my Function()
{
....
}
另外,c不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
现在,来看下面的函数,他会生成10个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:
int *getRandom()
{
static int r[10];
int i;
srand( (unsigned)time(NULL) );
for( i = 0; i < 10; ++i)
{
r[i] = rand();
printf("%d\n", r[i]);
}
return r;
}
int main()
{
int *p;
int i;
p = getRandom();
for( i = 0; i < 10 ; ++i)
{
printf("*(p + [%d]) : %d\n", i, *(p + i));
}
return 0;
}
Result:
1523198053 1187214107 1108300978 430494959 1421301276 930971084 123250484 106932140 1604461820 149169022 *(p + [0]) : 1523198053 *(p + [1]) : 1187214107 *(p + [2]) : 1108300978 *(p + [3]) : 430494959 *(p + [4]) : 1421301276 *(p + [5]) : 930971084 *(p + [6]) : 123250484 *(p + [7]) : 106932140 *(p + [8]) : 1604461820 *(p + [9]) : 149169022
TIPS: 1. 区别int *p[4] 和 int (*p)[4] int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。 int (*p)[4]; //定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型)。 注:原文基本来源于http://www.runoob.com/cprogramming/c-pointers.html