一、指针是一种数据类型
- 指针变量也是一种变量,占有内存空间,用来保存内存地址
测试指针变量占有内存空间大小。 - *p操作内存
在指针声明时,* 号表示所声明的变量为指针
在指针使用时,* 号表示操作指针所指向的内存空间中的值
*p相当于通过地址(p变量的值)找到一块内存,然后操作内存
*p放在等号的左边赋值(给内存赋值,写内存)
*p放在等号的右边取值(从内存获取值,读内存)
- 指针变量和它指向的内存块是两个不同的概念
规则1: 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;
p = p +1; //p++
规则2 :给*p赋值 *p=‘a’; 不会改变指针变量的值,只会改变所指的内存块的值
规则3 := 左边 *p 表示 给内存赋值, = 右边 *p 表示取值,含义不同切记!
规则4 :保证所指的内存块能修改
- 指针是一种数据类型,是指它指向的内存空间的数据类型
int a;
int *p = &a;
p++;
//指针步长(p++),根据所致内存空间的数据类型来确定。
//p++ 等价于 (unsigned char )p+sizeof(a);
- 当我们不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。指针指向谁,就把谁的地址赋值给指针
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//不断给指针赋值就是不断改变指针的指向
int main(void)
{
char buf[128];
int i;
char *p2 = NULL;
char *p1 = NULL;
p1 = &buf[0]; //不断的修改p1的值 相当于 不断改变指针的指向
p1 = &buf[1];
p1 = &buf[2];
for (i=0; i<10; i++)
{
//不断改变p1本身变量
p1 = &buf[i];
}
p2 = (char *)malloc(100);
strcpy(p2, "abcdefg1212333333333311");
for (i=0; i<10; i++)
{
//不断的改变p1本身变量,跟p1指向的内存块无关
p1 = p2+i;
printf("%c ", *p1);
}
return 0;
}
- 不允许向NULL和未知非法地址拷贝内存。
二、间接赋值(*p)是指针存在的最大意义
*p间接赋值成立条件: 三大条件
条件一: 2个变量(通常一个实参,一个形参)
条件二:建立关系,实参取地址赋给形参指针
条件三:*p形参去间接修改实参的值
int num = 0;
int *p = NULL; // 条件一:两个变量
p = # // 条件二:建立关系
Num = 1;
*p = 2 ; // 条件三:通过* 操作符, 间接的给变量内存赋值
间接操作:从0级指针到1级指针
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//使用一级指针
void getFileLen(int *p)
{
*p = 41; // p的值是file_len的地址 *p的地址间接修改file_len的值
//在被调用函数里面 通过形参 去 间接的修改 实参的值...
}
int getFileLen2()
{
int len = 100;
return len;
}
//不使用指针, 0级指针
void getFileLen3(int file_len)
{
file_len = 100;
}
//1级指针的技术推演
int main(void)
{
int file_len = 10; //条件1 定义了两个变量(实参 另外一个变量是形参p)
int *p = NULL;
p = &file_len; //条件2 建立关联
file_len = 20; //直接修改
*p = 30; //条件3 p的值是file_len的地址
// *就像一把钥匙 通过地址
// 找到一块内存空间 间接的修改了file_len的值
{
*p = 40; // p的值是a的地址 *a的地址间接修改a的值 //条件3 *p
printf("file_len: %d\n", file_len);
}
getFileLen(&file_len); //建立关联: 把实参取地址 传递给 形参
printf("getFileLen后 file_len: %d \n", file_len);
getFileLen3(file_len);
printf("getFileLen3后 file_len: %d \n", file_len);
return 0;
}
间接操作:从1级别指针到2级指针
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void getMem(char *p2)
{
p2 = 0x80088008;
}
void getMem2(char **p2)
{
*p2 = 0x40044004; //间接赋值 p2是p1的地址
}
int main(void)
{
char *p1 = NULL;
char **p2 = NULL;
//直接修改p1的值
p1 = 0x11001100;
//间接修改p1的值
p2 = &p1;
*p2 = 0x10101010; //间接赋值 p2是p1的地址
printf("p1:%p \n", p1);
{
*p2 = 0x20022002; //间接赋值 p2是p1的地址
printf("p1:%p \n", p1);
}
getMem(p1);
getMem2(&p1);
printf("p1:%p \n", p1);
return 0;
}
函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,来改变实参,把运算结果传出来。
用n级指针形参,去间接修改了n-1级指针(实参)的值。
三、理解指针必须和内存四区概念相结合
1) 主调函数 被调函数
a) 主调函数可把堆区、栈区、全局数据内存地址传给被调用函数
b) 被调用函数只能返回堆区、全局数据
2) 内存分配方式
a) 指针做函数参数,是有输入和输出特性的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getMem(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(void)
{
int ret = 0;
char *p1 = NULL;
int len1 = 0;
char *p2 = NULL;
int len2 = 0;
ret = getMem(&p1, &len1, &p2, &len2);
if (ret != 0)
{
printf("func getMem() 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;
}
return 0;
}
四、应用指针必须和函数调用相结合(指针做函数参数)
一级指针典型用法
一级指针做输入
int showbuf(char *p);
int showArray(int *array, int iNum);
输入:主调函数分配内存
一级指针做输出
int getLen(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); //避免野指针