1)指针也是一种变量,占有内存空间,用来保存内存地址 测试指针变量占有内存空间大小
2)*p操作内存 在指针声明时,*号表示所声明的变量为指针 在指针使用时,*号表示 操作 指针所指向的内存空间中的值 *p相当于通过地址(p变量的值)找到一块内存;然后操作内存 *p放在等号的左边赋值(给内存赋值) *p放在等号的右边取值(从内存获取值)
3)指针变量和它指向的内存块是两个不同的概念 //含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++ //含义2 给p赋值p=‘a’; 不会改变指针变量的值,只会改变所指的内存块的值 //含义3 =左边p 表示 给内存赋值, =右边p 表示取值 含义不同切结! //含义4 =左边char *p //含义5 保证所指的内存块能修改
4)指针是一种数据类型,是指它指向的内存空间的数据类型 含义1:指针步长(p++),根据所致内存空间的数据类型来确定 p++=➜(unsigned char )p+sizeof(a); 结论:指针的步长,根据所指内存空间类型来定。
注意:建立指针指向谁,就把把谁的地址赋值给指针。图和代码和二为一。 不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。
1)两码事:指针变量和它指向的内存块变量 2)条件反射:指针指向某个变量,就是把某个变量地址否给指针 3)*p间接赋值成立条件:3个条件 a)2个变量(通常一个实参,一个形参) b) 建立关系,实参取地址赋给形参指针 c) *p形参去间接修改实参的值
Int iNum = 0; //实参 int *p = NULL; p = &iNum; iNum = 1; *p =2 ; //通过*形参 == 间接地改变实参的值 *p成立的三个条件:4)引申: 函数调用时,用n指针(形参)改变n-1指针(实参)的值。 //改变0级指针(int iNum = 1)的值有2种方式 //改变1级指针(eg char *p = 0x1111 )的值,有2种方式 //改变2级指针的(eg char **pp1 = 0x1111 )的值,有2种方式
//函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,来改变实参,把运算结果传出来。 //指针作为函数参数的精髓。
1) 主调函数 被调函数 a) 主调函数可把堆区、栈区、全局数据内存地址传给被调用函数 b) 被调用函数只能返回堆区、全局数据 2) 内存分配方式 a) 指针做函数参数,是有输入和输出特性的。
指针做函数参数,问题的实质不是指针,而是看内存块,内存块是1维、2维。
如果基础类int变量,不需要用指针;若内存块是1维、2维。一级指针做输入
int showbuf(char *p) int showArray(int *array, int iNum)一级指针做输出
int geLen(char *pFileName, int *pfileLen);理解
主调函数还是被调用函数分配内存 被调用函数是在heap/stack上分配内存
二级指针做输入
int main(int arc ,char *arg[]); 字符串数组 int shouMatrix(int [3][4], int iLine);二级指针做输出
int Demo64_GetTeacher(Teacher **ppTeacher); int Demo65_GetTeacher_Free(Teacher **ppTeacher); int getData(char **data, int *dataLen); Int getData_Free(void *data); Int getData_Free2(void **data); //避免野指针理解
主调函数还是被调用函数分配内存 被调用函数是在heap/stack上分配内存
三级指针做输出
int getFileAllLine(char ***content, int *pLine); int getFileAllLine_Free(char ***content, int *pLine);理解
主调函数还是被调用函数分配内存 被调用函数是在heap/stack上分配内存
1)野指针 2种free形式
int getData(char **data, int *dataLen); int getData_Free(void *data); int getData_Free2(void **data);2)2次调用 主调函数第一次调用被调用函数求长度;根据长度,分配内存,调用被调用函数。 3)返回值char */int/char ** 4)C程序书写结构 商业软件,每一个出错的地方都要有日志,日志级别
1)指针也是一种数据类型,指针的数据类型是指它所指向内存空间的数据类型 2)间接赋值*p是指针存在的最大意义 3)理解指针必须和内存四区概念相结合 4)应用指针必须和函数调用相结合(指针做函数参数) 指针是子弹,函数是枪管;子弹只有沿着枪管发射才能显示它的威力;指针的学习重点不言而喻了吧。接口的封装和设计、模块的划分、解决实际应用问题;它是你的工具。 5)指针指向谁就把谁的地址赋给指针 6)指针指向谁就把谁的地址赋给指针,用它对付链表轻松加愉快 7)链表入门的关键是分清楚链表操作和辅助指针变量之间的逻辑关系 8)C/C++语言有它自己的学习特点;若java语言的学习特点是学习、应用、上项目;那么C/C++语言的学习特点是:学习、理解、应用、上项目。多了一个步骤吧。 9)学好指针才学会了C语言的半壁江山,另外半壁江山在哪里呢?你猜,精彩剖析在课堂。 10) 理解指针关键在内存,没有内存哪来的内存首地址,没有内存首地址,哪来的指针啊。
野指针产生的原因
//指针变量和它所指向的内存空间变量是两个不同的概念 //避免方法: //1)定义指针的时候,指针变量*p1初始化成nuLL 2)释放指针所指向的内存空间后,把它所指向的内存空间变量p1重置成NULL。 void main() { char *p1 = NULL; p1 = (char *)malloc(100); if (p1 == NULL) { return ; } strcpy(p1, "11112222"); printf("p1:%s \n", p1); if (p1 != NULL) { free(p1); p1 = NULL; } printf("hello...\n"); system("pause"); return ; }一级指针技术推演
int getFileLen(int *p) { *p = 41; //p的值是a的地址 *a的地址间接修改a的值 //在被调用函数里面 通过形参 去 间接的修改 实参的值... } //形参的属性 int getFileLen3(int b) { int i = 0; b = 100;//p的值是a的地址 *a的地址间接修改a的值 } //1级指针的技术推演 void main() { int a = 10; //条件1 定义了两个变量(实参 另外一个变量是形参p) int *p = NULL; //修改a的值 a = 20; //直接修改 p = &a; //条件2 建立关联 *p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值 printf("a: %d \n", a); { *p = 40; // p的值是a的地址 *a的地址间接修改a的值 //条件3 *p printf("a: %d \n", a); } getFileLen(&a); //建立关联: 把实参取地址 传递给 形参 printf("getFileLen后 a: %d \n", a); getFileLen3(a); //无法修改 printf("getFileLen3后 a: %d \n", a); printf("hello...\n"); system("pause"); return ; }二级指针技术推演
void getMem(char **p2) { *p2 = 400; //间接赋值 p2是p1的地址 } void getMem2(char *p2) { p2 = 800; //间接赋值 p2是p1的地址 } void main() { char *p1 = NULL; char **p2 = NULL; p1 = 0x11; p2 = 0x22; //直接修改p1的值 p1 = 0x111; //间接修改p1的值 p2 = &p1; *p2 = 100; //间接赋值 p2是p1的地址 printf("p1:%d \n", p1); { *p2 = 200; //间接赋值 p2是p1的地址 printf("p1:%d \n", p1); } getMem(&p1); getMem2(p1); printf("p1:%d \n", p1); system("pause"); return ; } int getMem3(char **myp1, int *mylen1, char **myp2, int *mylen2) { int ret = 0; char *tmp1, *tmp2; tmp1 = (char *)malloc(100); strcpy(tmp1, "1132233"); //间接赋值 *mylen1 = strlen(tmp1); //1级指针 *myp1 = tmp1; //2级指针的间接赋值 tmp2 = (char *)malloc(200); strcpy(tmp2, "aaaaavbdddddddd"); *mylen2 = strlen(tmp2); //1级指针 *myp2 = tmp2; //2级指针的间接赋值 return ret; } int main() { int ret = 0; char *p1 = NULL; int len1 = 0; char *p2 = NULL; int len2 = 0; ret = getMem3(&p1, &len1, &p2, &len2); if (ret != 0) { printf("func getMem3() err:%d \n", ret); return ret; } printf("p1:%s \n", p1); printf("p2:%s \n", p2); if (p1 != NULL) { free(p1); p1 = NULL; } if (p2 != NULL) { free(p2); p2 = NULL; } printf("p1:%d \n", p1); system("pause"); return ret; }间接赋值成立的三个条件
/* 条件1 //定义1个变量(实参) //定义1个变量(形参) 条件2 //建立关联:把实参取地址传给形参 条件3://*形参去间接地的修改了实参的值。 */ //间接赋值的应用场景 void main() { //1 2 3 这3个条件 写在有一个函数 //12 写在一块 3 单独写在另外一个函数里面 =====>函数调用 //1 23写在一块 ===>抛砖 ====C++会有,到时候,你别不认识...... char from[128]; char to[128] = {0}; char *p1 = from; char *p2 = to; strcpy(from, "1122233133332fafdsafas"); while (*p1 != '\0') { *p2 = *p1; p2 ++; p1 ++; } printf("to:%s \n", to); system("pause"); return ; }指针的输入与输出特性
//指针做输出:被调用函数分配内存 -----OK //指针做输入:主调用函数 分配内存 //求文件中的两段话的长度 int getMem(char **myp1, int *mylen1, char **myp2, int *mylen2) { char *tmp1 = NULL; char *tmp2 = NULL; tmp1 = (char *)malloc(100); if (tmp1 == NULL) { return -1; } strcpy(tmp1, "abcdefg"); *mylen1 = strlen(tmp1); *myp1 = tmp1; //间接修改实参p1的值 tmp2 = (char *)malloc(100); if (tmp2 == NULL) { return -2; } strcpy(tmp2, "11122233333"); *mylen2 = strlen(tmp2); *myp2 = tmp2; //间接修改实参p1的值 return 0; } int getMem_Free(char **myp1) { /* if (myp1 == NULL) { return ; } free(*myp1); //释放完指针变量 所致的内存空间 *myp1 = NULL; //把实参修改成nULL */ char *tmp = NULL; if (myp1 == NULL) { return -1; } tmp = *myp1; free(tmp); //释放完指针变量 所致的内存空间 *myp1 = NULL; //把实参修改成nULL return 0; } void main00() { char *p1 = NULL; int len1 = 0; char *p2 = NULL; int len2 = 0; int ret = 0; ret = getMem(&p1, &len1, &p2, &len2 ); printf("p1: %s \n", p1); printf("p2: %s \n", p2); getMem_Free(&p1); getMem_Free(&p2); system("pause"); return ; } int getMem_Free0(char *myp1) { if (myp1 == NULL) { return -1; } free(myp1); //释放完指针变量 所致的内存空间 myp1 = NULL; return 0; } void main01() { char *p1 = NULL; int len1 = 0; char *p2 = NULL; int len2 = 0; int ret = 0; ret = getMem(&p1, &len1, &p2, &len2 ); printf("p1: %s \n", p1); printf("p2: %s \n", p2); if (p1 != NULL) { free(p1); p1 = NULL; } if (p2 != NULL) { free(p2); p2 = NULL; } getMem_Free0(p1); //在被调用函数中 把p1所指向的内存给释放掉 ,但是 实参p1不能被修改成NULLL 有野指针现象 getMem_Free0(p2); system("pause"); return ; }