目录
一:指针偏移
指针是地址,可以偏移
指针偏移量是根据基础数据类型来决定的,示例如下:
示例一:int数据类型偏移量是4
#include<stdio.h>
int main()
{
int a=3;
int *p=NULL;//定义1 定义并赋初值
p=&a;
printf("a的地址:%p\n",p);//a的地址:0019FF2C
p++;
printf("a的地址:%p\n",p);//a的地址:0019FF30
return 0;
}
示例二:char数据类型偏移量是1
#include<stdio.h>
int main()
{
char name[6]="admin";
char* pt = name;
printf("name的地址是:%p\n",pt);//name的地址是:0019FF28
pt++;
printf("name的地址是:%p\n",pt);//name的地址是:0019FF29
}
如上对比分析,不难看出,指针的偏移量是根据基础数据类型决定的
二:指针应用
例如可将 控件添加函数 迭代更新,具体如下
当 ctrlCount控件数量 用int数据类型修饰传参的时候 需要 return返回 int 函数类型
int addControl(CONTROL_T ctrl,CONTROL_T ctrlArr[20] , int ctrlCount)
{
ctrlArr[ctrlCount++]=ctrl;//通过下标将控件ctrl放到控件数组ctrlArr[20]当中
// ctrlCount记录控件总个数 添加控件其下标数
return ctrlCount;
}
而现在学习了指针,可以使用 int *数据类型修饰 ctrlCount ,使用 *取地址中的值,无需return返回 直接使用void 函数类型 即可
void addControl(CONTROL_T ctrl,CONTROL_T ctrlArr[20] , int *ctrlCount)
{
ctrlArr[(*ctrlCount)++]=ctrl;//通过下标将控件ctrl放到控件数组ctrlArr[20]当中
// ctrlCount记录控件总个数 添加控件其下标数
}
也就是按值传递变成按地址传递,函数内部改变,外部也可以变
若是按值传递则需要返回,如int类型数据 return返回,外部才可以获取信息
但是采用按地址传递,就不用返回,函数类型可以直接设置为void
对指针数据类型 如上 int*函数参数 在传参(函数调用的时候) 需要 &取地址 传递函数参数 ,如下示例
添加控件函数的调用:addControl(title,loginWin.ctrlArr,&loginWin.ctrlCount);//通过地址获取信息
三:有关指针的小练习
1.定义一个int类型的变量 ,定义一个int类型指针 接受变量的地址
2.定义一个char类型的字符数组[10] ,定义一个char类型指针 接受变量的地址,( 获取下标为5的元素)
结果如下:
#include<stdio.h>
int main()
{
int a=1;
char name[10]="abcdefgh";
int *p=NULL;//定义并赋初值
char*pt=NULL;//定义并赋初值
p=&a;//int 取a的值
pt=name;//char 取name数组内容
printf("打印int a的地址%p\n",p);//整型a地址 打印int a的地址0019FF2C
printf("打印int a的值%d\n",*p); //整型a值 打印int a的值1
printf("打印char name下标5元素地址%p\n",pt);//打印char name下标5元素地址0019FF20
printf("打印char name下标5元素的值%c\n",*(pt+5));//下标为5值 打印char name下标5元素的值f
return 0;
}
四:指针 & 数组
1.数组的指针就是数组的起始地址就是数组名
数组的指针是常量指针【不可以改变】,示例如下
#include<stdio.h>
void test1()
{
int numArr[5]={0,1,2,3,4};
int *p=numArr;
printf("%p\n",p); //0019FEC8
printf("%p\n",numArr);//0019FEC8
printf("%p\n",p+2); //0019FED0 指针偏移
printf("%p\n",numArr+2); //0019FED0 指针偏移
}
int main()
{
test1();
return 0;
}
2.指针偏移【两种写法】
写法一: 先指针变量存储数组地址,后再指针变量偏移,示例如下
#include<stdio.h>
void test1()
{
int numArr[5]={0,1,2,3,4};
int *p=numArr;
p+=2;
printf("%d %p\n",*p,p);//2 0019FED0
}
int main()
{
test1();
return 0;
}
写法二: 在指针变量存储数组地址的同时,直接指针变量偏移
#include<stdio.h>
void test1()
{
int numArr[5]={0,1,2,3,4};
int *p = numArr+2;
printf("%d %p\n",*p,p);//2 0019FED0
}
int main()
{
test1();
return 0;
}
五:指针变量操作一维数组
指针访问数组【两种方式】
1. 指针[下标]方式
2. 指针偏移量方式
指针[下标]方式 & 指针偏移量方式 操作一维数组,示例如下
#include<stdio.h>
void test1()//指针变量操作一维数组
{
int numArr[5]={0,1,2,3,4};
int *p=numArr;
//数组名是起始地址 第一个元素的地址
printf("%d %p\n",*p,p);//0 0019FEC8
printf("%d\n",numArr[1]);//1 指针下标
printf("%d\n",p[2]); //2 指针下标
printf("%p\n",p+2); //0019FED0 指针偏移
}
int main()
{
test1();
return 0;
}
保存第二个元素的地址 示例:
#include<stdio.h>
void test1()//指针变量操作一维数组
{
int numArr[5]={0,1,2,3,4};
int *p=numArr;
//保存第二个元素的地址
p=&numArr[1];
printf("%d\n",*p);//1
printf("%p\n",p); //0019FECC
}
int main()
{
test1();
return 0;
}
查看第四个元素的值 示例:
#include<stdio.h>
void test1()//指针变量操作一维数组
{
int numArr[5]={0,1,2,3,4};
int *p=numArr;
printf("%d\n",*(numArr+3));//3 *取值
}
int main()
{
test1();
return 0;
}
注意点:写法numArr++不可以(是错误的写法),因为 指针变量才可以++,而数组地址(常量)系统开辟空间是固定的,不可以++【数组的指针是常量指针,不可以++】
数组的访问方式:
数组名[下标]
*(数组名+偏移量)
数组作为参数(三种表示)
char str[10]
char str[ ]
char *str
数组作为返回值,函数类型如char* demo1(){代码} return "admin";
(char类型返回,则函数类型为char*)
当然也有如int* demo2(){代码},函数类型是int *
六:指针变量操作字符数组
数组的访问方式:
数组名[下标]
*(数组名+偏移量)
#include<stdio.h>
void test2()//指针变量操作字符数组
{
char name[6]="admin";
char *pt=name;
printf("%s\n",name);//admin
printf("%s\n",pt); //admin
printf("%c\n",name[1]); // d
printf("%c\n",*(pt+1)); // d *(指针变量+偏移量)
}
int main()
{
test2();
return 0;
}
字符数组元素可以修改 示例如下
#include<stdio.h>
void test2()//指针变量操作字符数组
{
char name[6]="admin";
char *pt=name;
name[1]='s'; //字符数组元素修改
printf("%s\n",name); //asmin
printf("%s\n",pt); //asmin
printf("%c\n",name[1]); // s
printf("%c\n",*(pt+1)); // s *(指针变量+偏移量)
}
int main()
{
test2();
return 0;
}
字符常量指针元素不可以修改,示例如下,会出现程序异常现象
#include<stdio.h>
void test2()
{
char *ps="hello"; //字符串常量 存储在常量区
ps[1]='a'; //常量不可修改 程序运行会出现异常
printf("%s\n",ps);//程序异常,没有任何打印
printf("%c\n",*(ps+1));
}
int main()
{
test2();
return 0;
}
七:字符数组 & 字符指针 作为函数返回值
#include<stdio.h>
char *test1() //(字符数组作为返回值)
{
char name[6]="lily"; //局部变量系统回收
return name;
}
char *test2() //(字符指针作为返回值)
{
char *str="hello"; //字符常量指针 常量区 可以正常打印hello
return str;
}
int main()
{
char *ps=NULL,*pt=NULL;
ps=test1();
pt=test2();
printf("%s\n",ps);//0.
printf("%s\n",pt);//hello
return 0;
}
可以看出字符数组作为返回值,打印出信息非理想信息,也就是说在字符数组作为返回值的时候,系统回收
而字符指针作为返回值,常量区不会被回收,因此可以打印出hello完整信息
对于字符数组作为返回值解决如下:
字符数组作为参数传入,示例如下
#include<stdio.h>
void test3(char *name)//字符数组作为参数传入
{
name[0]='s';
} //内部传参进行修改,外部即可以获取
int main()
{
char str[10]={0};
test3(str);
printf("%s\n",str);//s
return 0;
}
八:存储类别
内存中的存储区域包括有:
程序代码区:存放函数体的二进制代码
静态区/全局区(static):全局变量和静态变量的存储区域
堆区(heap):程序员分配释放
栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值