目录
间接赋值(<*p>是指针存在的最大意义)
1级指针的间接赋值推演
如下是一个在主函数main中,通过*p间接改变变量a的值(将原理的10改成30,再将30改成40),思路很简单,不再赘述。
//1级指针的技术推演
void main32()
{
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);
}
printf("hello...\n");
system("pause");
return ;
}
接着进行进一步推演,如果把
*p = 40; // p的值是a的地址 *a的地址间接修改a的值 //条件3 *p
给单独置成一个函数,放在主函数外面,也可以达到同样的效果吗?于是,将其封装成一个函数,
int getFileLen(int *p)
{
*p = 41; // p的值是a的地址 *a的地址间接修改a的值
//在被调用函数里面 通过形参 去 间接的修改 实参的值...
}
再在主函数中调用,
getFileLen(&a); //建立关联: 把实参取地址 传递给 形参
printf("getFileLen后 a: %d \n", a);
实现的功能和原来一样。 那么重要的来了:通过被调用函数去间接的修改了a的值,即我们可以通过一个函数把运算结果给甩出来,这正是一个很重要的功能。通过形参去间接的修改实参的值。这个正是通过指针来进行程序内存调用的强大优势,在不添加多余内存空间的同时,可以通过外部函数形参改变主函数中的值,既节省空间,有便捷高效。
那么,如果不用指针做函数参数,直接通过间接赋值的方式,可不可以呢?同样,也在主函数外面设置一个子函数getFileLen3。来进行值对值的间接修改。
//形参的属性
int getFileLen3(int b)
{
b = 100;// p的值是a的地址 *a的地址间接修改a的值
}
在主函数中进行调用,
getFileLen3(a);
printf("getFileLen3后 a: %d \n", a);
答案是否定的,通过子函数getFileLen3这样的方法,是修改不了原函数内容的。因为在子函数getFileLen3运行结束的同时,它的所有值也都给析构了,根本不会对原函数造成任何的影响。(详情请见Record02部分记述)
从1级指针到2级指针的间接赋值推演
先来个2级指针看看,
void main33()
{
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);
}
printf("p1:%d \n", p1);
system("pause");
return ;
}
需要说的是,p1是一个1级指针,p2是一个2级指针,p2放的是p1的地址,换句话说,p2是p1的指针。运行出来之后,
这说明2级指针很容易的把1级指针给修改了。那么,下面还是把2级指针间接修改的部分给提出到主函数外面去,变成一个子函数,
void getMem(char **p2)
{
*p2 = 400; //间接赋值 p2是p1的地址
}
再在主函数中进行调用,
getMem(&p1);
printf("p1:%d \n", p1);
运行显示,的确修改了值,
2级指针在被调用函数里面,去间接的修改1级指针的值。 需要注意的是给被调用函数传参的时候,传的是1级指针的地址,需要用取地址符(&p1),在被调用函数的形参头上,应该是"char **p2"双星号才对。那么为啥单星号不行呢?那么改一下试试,
void getMem2(char *p2)
{
p2 = 800; //间接赋值,改变指针指向内存地址为800的地方,并且,随着被调用函数运行结束后,析构
//所有被调用函数中的内容都将被擦除。
}
在主函数中进行调用,
getMem2(p1);
printf("p1:%d \n", p1);
答案肯定是不行的,原理和之前的调用值来间接改变值是一样的,因为在getMem2结束运行后,其所有内容就析构了,于主函数中的值来说,没有任何改变。(详情请见Record02部分记述)。故,要想修改p1的值,只有把p1的地址,扔给被调用函数来进行修改!只把变量本身扔给被调用函数,相当于改变指针指向的内存,并不是改变指针指向内存空间的值。
间接赋值的工程应用
下面是一个用1、2级指针来间接赋值的案例,
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 main35()
{
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;
}
一个main函数可以配套很多子函数,而这种通过指针作函数参数,实现了间接赋值,实现了模块之间的一个分层和联合。如果没有这种间接赋值的方法,就不可能有函数之间的分层;没有分层就不可能有函数之间的接口和封装的设计;没有封装和设计,就不可能有功能和功能之间的划分。没有软件之间功能与功能之间的划分,就不可能有软件信息系统;没有软件信息系统,就没有程序员了!
C语言精华:通过指针作函数参数,使不同的函数可以同时操作一块儿内存空间。通过不同的首地址把内存空间给传过去,同时,把运算结果在多个函数中进行运算和分解,精华莫过如此。
间接赋值存在的条件(需牢记)
一个函数内:
条件1,定义两个变量
条件2,建立关联
条件3,通过*p,找到一个地址,去间接的修改这个地址内的值
多个函数之间:
条件1,定义两个变量,一个是实参,另一个是形参
条件2,建立关联,把实参取地址扔给形参
条件3,被调用函数里面,通过形参去间接的修改实参的值
间接赋值的应用场景
以上的三个条件,不同组合,变成不同的应用场景。下面的代码是举1,2,3在同一个函数里面的例子,
//间接赋值的应用场景
void main37()
{
//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 ;
}
运行结果如下:
间接赋值的推论
在函数调用的时候,
用1级指针形参,去间接修改0级指针(实参)的值。
用2级指针形参,去间接修改1级指针(实参)的值。
用3级指针形参,去间接修改2级指针(实参)的值。
用n级指针形参,去间接修改n-1级指针(实参)的值。
总体代码
dm03_间接赋值的技术推演.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//return 只能返回一个结果
//
int getFileLen2()
{
int a = 100;
return a;
}
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 main32()
{
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 main33()
{
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 main35()
{
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 main37()
{
//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 ;
}