常量指针与指针常量
int n;
const int * pc = &n; // pc定义为常量指针类型,不能通过pc改变指向地址中存的值,但pc指向地址可变
// *pc = 2; // Error: n cannot be changed through p without a cast
pc = NULL; // OK: pc itself can be changed
int * const cp = &n; // cp是一个指针常量类型,指向的地址是定值,不可通过cp改变指向地址,但地址中存的值可变
*cp = 2; // OK to change n through cp
// cp = NULL; // Error: cp itself cannot be changed
int * const * pcp = &cp; // non-const pointer to const pointer to non-const int
指针与数组的关系
数组名就是指向数组中第一个元素的地址,可以把它理解为指针,不过是本身指向地址为常量的指针罢了(指针常量),这点我觉得这个老哥说得特别好,
*a就是指向地址中的值,这里有一点要说明一下:
C语言中地址默认是按行增长的,这里就拿数组地址按行增长来说
一维数组
#include<stdio.h>
int main()
{
int a[3]={7,8,9};
printf("%d\n",*(a+1));//a的指向由原来的指向7的地址,变为指向8的地址
return 0;
}
二维数组
#include<stdio.h>
int main()
{
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
printf("%d\n",**(a+1));//a的指向由原来的指向1的地址,变为指向4的地址
return 0;
}
但是除了这片地址之外就满足指针常量的性质,指向其它地址就会报错。因为数组名是指针常量,所以它不能做为被赋值的对象,不可当变量使用
自己对指针的一些理解
指针关键要看两个地址,一个是指针本身的地址还有就是指针中存储的地址,只要围绕这两个的东西来看指针无论是二极指针、结构体指针、数组指针都离不开这两个东西,理清这两个东西也是分析问题的关键
int *p;
int *q;
int a=5;
int b[3];
p=&a; //不是地址的借助 &运算符获得地址
p=b; //是地址的直接赋值
p=q; //指针之间的赋值结果是把q指向的地址赋值给p,让q和p指向同一个地址
自己平时查看地址的一些错误纠正
#include<stdio.h>
int main()
{
int *p=0;//看看他们的地址分别是什么?
int *q;
int c=4;
printf("p init adder is:%p\n",&p);//这个打印的才是自己的地址
printf("p init value is:%p\n",p);//这个打印的不是p本身的地址,而是p指向的地址,不信我们再做一个给p赋值为NULL的测试,已经证实了
printf("q init adder is:%p\n",&q);
printf("q init value is:%p\n",q);
p=&c;
printf("&c adder is:%p\n",&c);
printf("c adder is:%p\n",c);//这里要重新申明一下%p的用法,虽然说是用来打印地址的,但用printf来打印时一定得满足%p对应的是一个地址,而不是一个值,否则打印的是值而不是地址,只不过值前面加了个0x罢了,并不是地址
printf("p equaled adder is:%p\n",&p);
printf("p equaled value is:%p\n",p);//p和&(*p)打印的是同一个地址
printf("*p adder is:%p\n",&(*p));
return 0;
}
测试结果:
p init adder is:0x7ffe5e522548
p init value is:(nil)
q init adder is:0x7ffe5e522550
q init value is:0x7ffe5e52257e
&c adder is:0x7ffe5e522544
c adder is:0x4
p equaled adder is:0x7ffe5e522548
p equaled value is:0x7ffe5e522544
*p adder is:0x7ffe5e522544
函数指针
指针函数与函数指针,说实话这两个字眼有时候就是考语文
函数指针:一个用来指向函数的指针,本质是一个指针,常见代码形式 int (*func)(int x,int y)
指针函数:一个函数的返回值是指针,本质是一个函数,常见代码形式 int * func(int x,int y)
带参数的函数指针
google@ubuntu1404:~/workspace/test/play_game$ cat test.c
#include<stdio.h>
//有参数的情况 :
void single_life( void(*function)(int arg),int a );
void function(int arg);
void single_life( void(*function)(int arg),int a )
{
function(a);//通过函数指针调用带参数的函数
}
void function(int arg)
{
int a=arg;
while(a)
{
printf("奥里给 ,打工人!\n");
sleep(3);
}
}
void main()
{
single_life(function,1);
}
google@ubuntu1404:~/workspace/test/play_game$ gcc test.c
google@ubuntu1404:~/workspace/test/play_game$ ./a.out
奥里给 ,打工人!
奥里给 ,打工人!
奥里给 ,打工人!
^C
google@ubuntu1404:~/workspace/test/play_game$
不带参数的函数指针
google@ubuntu1404:~/workspace/test/play_game$ cat test.c
#include<stdio.h>
//没参数的情况 :
void single_life( void(*function)(void *arg));
void function(void *arg);
void main()
{
single_life(function);
}
void single_life( void(*function)(void *arg) )
{
function(0);//由于没有带参数所以通过函数指针调用的时候直接写0,但不能不写不然会抛错
}
void function(void *arg)
{
while(1)
{
printf("加油 ,打工人!\n");
sleep(3);
}
}
google@ubuntu1404:~/workspace/test/play_game$ gcc test.c
google@ubuntu1404:~/workspace/test/play_game$ ./a.out
加油 ,打工人!
加油 ,打工人!
加油 ,打工人!
加油 ,打工人!
^C
google@ubuntu1404:~/workspace/test/play_game$
函数指针作为结构体的成员
google@ubuntu1404:~$ gcc tt.c
google@ubuntu1404:~$ ./a.out
hello world!
google@ubuntu1404:~$ cat tt.c
#include <stdio.h>
typedef struct a
{
void (*func)(char *);
}a_t;
void hello(char *name)
{
printf ("%s\n",name);
}
int main()
{
#if 0
//version 1 结构体成员初始化
a_t a1;
a1.func = hello;
a1.func("hello world!");
#endif
#if 1
//version 2 结构体成员初始化
a_t a1={hello};
a1.func("hello world!");
#endif
return 0;
}
google@ubuntu1404:~$
参考博文:https://www.cnblogs.com/xiaolongxia/articles/2752731.html