一、指针:
对于指针,我就不介绍概念了,很多教材讲的比我好的多。我在这里归纳一下指针操作需要注意的点:
1. 在进行函数传参时,数组传址,其它类型传值,但进行局部变量通过其它函数改变值时要传址。
如int a=1;则函数形参应该写int *x; 传参时实参应该为&a;
但传址时,函数中对形参指向进行改变,不影响原函数中实参的指向。
比如原函数中实参a->地址1,传参时形参b->地址1,将b换值不影响a的指向。
2. 二维数组情况下,有下图关系(理解此图,指针基础操作不在话下):
3. 二维数组作形参的三种方式:分别是int b[][6],int (*b)[6],int **b。其中前两种二维不能省略,第三种传参以后得到的实际上是一个一维数组,注意操作方式。
4. c储存字符串的两种方式:一是字符数组,而是字符指针。但这两种方式储存字符串的方式是不同的,字符数组每一个单元存放一个值,而字符指针存放的只是字符串的首地址。在系统编译时,字符指针只有一个4字节的空间用于存放地址,而字符数组则有一系列连续的空间存放值。
对于字符指针,可以像c++种string类型那样直接赋值,可以puts()输出,可以像字符数组一样用下标访问,可以和字符指针用等号进行赋值,但在使用字符指针一定要记得赋初值,否则指针的指向是未定的,使用野指针很危险。当然使用字符指针时,若不打算赋初值,也可以配合动态数组开辟一定的空间把地址给字符指针,但要注意此时字符指针的地址已经改变。
对于字符之间的赋值,字符指针之间可以之间用等号。但对于字符指针a和字符数组b,首先不能用等号是自然,其次对于字符复制函数,strcpy(a,b)不行,strcpy(b,a)则可以(这应该与编译原理有关),要进行第一种操作,应该写成a = &b[0]或者a=&b,或者给a开辟一定空间。
5. 函数的指针:首先函数名就是函数的首地址,函数名就是函数的指针。如有一个函数int max(int a,int b); 则指向这个函数的指针p应该定义为int (*p)(int,int),然后p=max。调用时(*p)(a,b)即可。
若要返回指针,对函数类型进行相应修改即可。
6. 指针数组:char * name[ ] = {"aaa", "bbb", "ccc"}; name中三个元素分别存放三个字符串首地址,puts(name[i]);可分别输出三个字符串。
7. 指针的指针:char * name[ ] = {"aaa", "bbb", "ccc"}; char **p; p=name; puts(*(p+i)); 可分别输出三个字符串。
指针数组和指针的指针在字符串上的作用比较直接,其它情况类似,但目前遇到这些情况的实际应用,以后遇到再补充。
二、 动态数组:
1. int *p; p=(int *)malloc(sizeof(int)); //开辟1块int大小的空间,将其强制转换为int型指针,地址给p。
2. int *p; p=(int *)calloc(5,sizeof(int)); //开辟5块int大小的连续空间,将其首地址强制转换为int型指针,给p。
2. free(p); //释放申请的空间,不释放容易造成内存泄漏。
三、 编译预处理:
1. 宏定义:#define PI 1e6+5
2. 文件包含:系统文件:#include <stdio.h>,自定义文件#include "gaoithe.h"。
3. 条件编译:
//第一种:如果标识符被定义,执行程序段1,否则执行程序段2
#ifdef 标识符
程序段1
#else
程序段2
#endif
//第二种:表达式值为真,执行程序段1,否则执行程序段2
#if 常量表达式
程序段1
#else
程序段2
#endif
4. 补充一个不是编译预处理但类似的,即变量名替换:typedef long long LL;