强化1:指针是一种数据类型
1) 指针变量也是一种变量,占有内存空间,用来保存内存地址
测试指针变量占有内存空间大小。
2) *p操作内存
在指针声明时,* 号表示所声明的变量为指针
在指针使用时,* 号表示操作指针所指向的内存空间中的值
*p相当于通过地址(p变量的值)找到一块内存,然后操作内存
*p放在等号的左边赋值(给内存赋值,写内存)
*p放在等号的右边取值(从内存获取值,读内存)
3)指针变量和它指向的内存块是两个不同的概念。
4)指针是一种数据类型,是指它指向的内存空间的数据类型 。
int a;
int *p = &a;
p++;
指针步长(p++),根据所致内存空间的数据类型来确定。
5 ) 当我们不断的给指针变量赋值,就是不断的改变指针变量
(和所指向内存空间没有任何关系)。指针指向谁,就把谁的地址赋值给指针。
#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;
}
6 ) 不允许向NULL和未知非法地址拷贝内存。
强化2:间接赋值(*p)是指针存在的最大意义
*p间接赋值成立条件: 三大条件
条件一: 2个变量(通常一个实参,一个形参)
条件二:建立关系,实参取地址赋给形参指针
条件三:*p形参去间接修改实参的值
int num = 0;
int *p = NULL; // 条件一:两个变量
p = # // 条件二:建立关系
Num = 1;
*p = 2 ; // 条件三:通过* 操作符, 间接的给变量内存赋值
强化3: 间接操作: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;
}
输出结果
file_len: 40
getFileLen后 file_len: 41
getFileLen3后 file_len: 41
强化4:从1级别指针到2级指针
#include <stdlib.h>
#include <stdio.h>
void getMem(char *p2)
{
p2 = (char*)0x80088008;
}
void getMem2(char **p2)
{
*p2 = (char*)0x40044004; //间接赋值 p2是p1的地址
}
int main(void)
{
char *p1 = NULL;
char **p2 = NULL;
//直接修改p1的值
p1 = (char*)0x11001100;
//间接修改p1的值
p2 = &p1;
*p2 = (char*)0x10101010; //间接赋值 p2是p1的地址
printf("p1:%p \n", p1);
{
*p2 = (char*)0x20022002; //间接赋值 p2是p1的地址
printf("p1:%p \n", p1);
}
getMem(p1);
getMem2(&p1);
printf("p1:%p \n", p1);
system("pause");
return 0;
}
运行结果:
p1:10101010
p1:20022002
p1:40044004
• 间接赋值的推论
用1级指针形参,去间接修改了0级指针(实参)的值。
注意这里的0级指针指的是普通类型变量
用2级指针形参,去间接修改了1级指针(实参)的值。
用3级指针形参,去间接修改了2级指针(实参)的值。
用n级指针形参,去间接修改了n-1级指针(实参)的值。
• 间接操作:应用场景 strcpy函数
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * Mystrcpy(char *dest,const char *src)
{
char * temp = dest;
if(dest==NULL||src==NULL)
{
return NULL;
}
while(*dest++ = *src++)
{
}
return temp;
}
int main()
{
char buf[] = "hello,world";
int len = strlen(buf);
char *buf1 = (char*)malloc(sizeof(buf1)+1);
if(buf1==NULL)
{
return -1;
}
Mystrcpy(buf1,buf);
printf("buf1:%s\n",buf1);
if(buf1!=NULL)
{
buf1=NULL;
free(buf1);
}
system("pause");
return 0;
}
强化5:理解指针必须和内存四区概念相结合
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;
}
输出结果
p1:1132233
p2:aaaaavbdddddddd
应用指针必须和函数调用相结合(指针做函数参数)
经典语录
1)指针也是一种数据类型,指针的数据类型是指它所指向内存空间的数据类型
2)间接赋值*p是指针存在的最大意义
3)理解指针必须和内存四区概念相结合
4)应用指针必须和函数调用相结合(指针做函数参数)
指针是子弹,函数是枪管;子弹只有沿着枪管发射才能显示它的威力;
指针的学习重点不言而喻了吧。接口的封装和设计、模块的划分、
解决实际应用问题;它是你的工具。
5)指针指向谁就把谁的地址赋给指针
6)C/C++语言有它自己的学习特点;若java语言的学习特点是学习、应用、
上项目;那么C/C++语言的学习特点是:
学习、理解、应用、上项目。多了一个步骤。
7) 理解指针关键在内存,没有内存哪来的内存首地址,
没有内存首地址,哪来的指针。