概述
文章目录
- 指针
- 指针的应用场景
- 指针常见错误
- 指针与const
- 指针的运算
- 动态分配
- 字符串操作
- putchar
- getchar
- 字符串数组
- 字符串函数的一些套路
- 结构类型
- 枚举
- 结构
- 结构与函数
- 结构数组
- 类型的定义
- 联合
- 链表
- 可变数组
- 链表
- 程序结构
- 全局变量
- 静态本地变量
- *返回指针的函数
- 关于全局变量的一些贴士
- 宏定义与编译预处理指令
- 大程序结构
- 头文件
- 声明
- 函数指针及其应用
- 文件
- 输入,输出格式
- 输出
- 输入
- 文件输入输出
- FILE
- 二进制文件
- 二进制读写
- 位运算
- 按位运算
- 位段
指针
指针的应用场景
- 交换两个变量
- 函数返回多个值,某些值就只能通过指针返回
- 传入的参数实际上是需要保存带回的结果的变量
int a[]={1,2,3,4,5,6,7,12,36,45,98};
int min,max;
minmax(a,sizeof(a)/sizeof(a[0],&min,&max);
printf("min=%d,max=%dn",min,max);
void minmax(int a[],int len,int *min,int *max)
{
int i;
*min=*max=a[0];
for(i=1;i<len;i++){
if(a[i]<*min){
*min=a[i];
}
if(a[i]>*max){
*max=a[i];
}
}
}
- 函数返回运算的状态,结果通过指针返回,让函数返回特殊的不属于有效范围内的值来表示出错。但是当任何数值都是有效的可能结果时,就得分开返回了。java中利用异常机制处理
- 需要传入较大的数据时用作参数
- 传入数组后对数组做操作
- 需要用函数来修改不止一个变量
- 动态申请内存时
指针常见错误
- 定义了指针变量,还没有指向任何变量,就开始使用指针
指针与const
int *const q=&i;//指针是const,后面不能在指向其他
int *const q=&i;//表示一旦得到了某个变量的地址,不能再指向其他变量,q是const
*q=26;//没问题
q++;//错误
const int*p=&i;//不能通过这个指针去修改那个变量
const int*p=&i;
//表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)
*p=26;//错误,(*p)是const
i=26;//可以这样写
p=&j;//可以这样写
判断方式:看const在*前面还是后面,
- const在*前:它所指的东西不能通过指针被修改;
- const在*后,表指针不能被修改指向其他变量
- 总是可以把一个非const的值转换成const的。
- void f(const int*x);//在函数内部,不会更改指针所指的变量值
- 当要传递的参数的类型比地址大的时候,这是常用的手段:即能用比较少的字节数传递给参数,又能避免函数对外面的变量修改
- const int a[]={1,2,3,4,5,6,};数组变量已经是const的指针了,而这里的const表明数组的每个单元都是const int
- 因为把数组传入函数时传的是地址,所以那个函数内部可以修改数组的值
- 为了保护数组不被函数破坏,可以设置参数为const
- int sum(const int a[],int length)
指针的运算
- 当给指针+1;就是给这个指针指的那个类型的地址加相对的sizeof个字节数(sizeof (int)==4)
- *(p+1)指的是先运算再取加1后的地址
- 对于数组来说
char *p=ac;
*(p+n)<——>ac[n]
- 两个指针相减:这两个地址之间能放几个这样类型的东西,即这两个地址的差除sizeof(对应类型)所得的数
- *p++:取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
- *的优先级比++低
- 常用于数组类的连续空间操作
如利用指针循环遍历数组
int main(int argc,char const *argv[])//这样写参数不用return 0;
{
char ac[]={0,1,2,3,4,5,6,-1};
//-1不是有效数字
char *p=&ac[0];
while(*p!=-1){
//也可以用for(p=ac;*p!=-1; )
printf("%dn",*p++);
}
return 0;
}
- 指针可以做>、<、=、!=等,也就是比较它们在内存中的地址,数组单元的地址线性递增
- 有虚拟的0地址,但0地址通常是不能碰的,所以指针不应该具有0值,因此可以用0地址来表示特殊的事情
- 返回的指针是无效的
- 指针没有被真正的初始化(先初始化为0)
- NULL是c语言预定义的符号,表示0地址
- 有的编译器不允许你用0来表示0地址
指向不同类型的指针不能直接相互赋值
- 但指针可以进行强制类型转换 ,(尽量不要这么干)
- int *p=&i;void*q=(void*)p; 这并没有改变p所指的变量类型,而是让后人用不同的眼光通过q看,看做他所指的变量是个void
- void*表示不知道指向什么东西的指针
- 计算时与char相同,但不相通
动态分配
- C99可以用变量做数组定义的大小
- 动态分配
int *a=(int*)malloc(n*sizeof(int));
,(n个int的空间)后面可以将a当做数组使用 - 动态申请使用了之后再
free(a);
,只能还申请来的空间的首地址,比如指针p在p++后再free(p)是不行的。free(NULL)是可以的,这是为了有个好习惯 - free过再free,地址变过再free,free的不是申请来的,都是不被允许的
- 向malloc申请的空间的大小是以字节为单位的,返回的结果是void*,需要类型转换为自己需要的类型,申请失败则返回0或NULL
字符串操作
putchar
- int putchar(int c);
- 向标准输出写一个字符
- 返回写了几个字符,EOF(-1)表示写失败
getchar
- int getchar(void);
- 从标准输入读入一个字符
- 返回类型是int是为了返回EOF(-1)
字符串数组
- char **a
- a是一个指针,指向另一个指针,那个指针指向一个字符(串)
- char a[ ][10 ]指每一个 都有10个字符的空间
- char *a[ ],a[0]相当于char*,a[0]指向外面某一处空间,a[1]也是等等
字符串函数的一些套路
- 复制一个字符串常用的套路:
char*dst=(char*)malloc(strlen(src)+1);
//+1是因为结尾的0
strcpy(dst,src);
char s[]="Hello";//找到l前面的,并输出
char *p=strchr(s,'l');//找到第一个l
char=strchr(p+1,'l');//从第一个l后再找l并输出这后面所有字符
printf("%sn",p);
char s[]="Hello";//找到l前面的,并输出
char *p=strchr(s,'l');//找到l,此时p指向的是第一个l
char c=*p;//c暂存此时p所指的值
*p='