1.指针基础定义和使用
char val='a';
char*p=&val; //定义指针指向val
char**q=&p;
char*pa,pb; //pa是char*,pb是char
char*pa,*pb; //pa,pb都是char*
typedef char* PChar;
PChar pa,pb; //pa,pb都是char*
#define PCHAR char*
PCHAR pa,pb; //值替换 char*pa,pb;
2.指针与const的结合
const int a=10;
int b=20;
//定义p指向a
const int *p=&a; //p具有常性
//p指向的值具有常性
int *const q=&a; //权限缩小 正确
//q具有常性
3.野指针和空指针
//野指针-悬挂指针-空悬指针
//所指地址不明确 随机地址:地址对应值没有访问权限
int *p; //野指针
*p=1; //崩
//空指针 NULL #define NULL 0
int *p=NULL; //0号地址空间不具有访问权限
//(内存前128M禁止访问)
*p=1; //崩
int *p=200000;//错误 类型错误 200000-->int
int *p=(int*)200000;//不建议 不安全
//*p崩
4.指针运算
4.1指针加整型
int val=10;
int *p=&val; //*p解析4B空间
//*p解析的内存大小 取决于*p的类型
char num='a';
char *pn=#
*pn -- 解析1字节内存空间 *pn类型
4.2指针+n/-n
p+1能力 指针偏移量 从p所指地址开始向高地址偏移1
p-1能力 低地址偏移1
指向1*sizeof(*p)位置 类型不变 p+1的类型: int *
基于连续地址空间 谈论指针相减
p与q之间相差的元素数量 p-q
4.3指针++/--
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int *p = arr+2; 开始时指向arr[2] -- 3
*p++ --> 3 先解引用,表达式的值为3 后P的指针指向加一,指向arr[3]
*++p --> 5 p先自增,后解引用 -- 5
++(*p) --> 6 ++ --> 自增操作,P指向的值不变,将arr[4]的值自增1
(*p)++ --> arr[4] = arr[4]+1 先解引用,在自增
*--p --> arr[3]:4
--*p --> arr[3] = arr[3] - 1 --> 3
4.4数据在内存中的存储方式(面试题)
int val = 0x12345678
存储模式:
大端模式(大端字节序): 高位数据存储低地址位置(高低/低高)
低地址 高地址
0x12 0x34 0x56 0x78 --- > 0x12345678
小端模式(小端字节系): 低地址位置存储低位数据(低低/高高)
低地址 高地址
0x78 0x56 0x34 0x12 // ---> 0x12345678
大端模式,指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。
小端模式,指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
验证大小端模式:、
int val = 0x12345678;
char* p = (char*)&val; // *p --> 0x12345678
if(*p == 0x78) 小
else 大端
5.指针数组
是一个数组,每个元素值类型 地址-->指针数组
int a,b,c;
int *pa=&a,*pb=&b,*pc=&c;
int *arr[]={&a,&b,&c};
const char* srr[]={"hello","abc","def"};
char str[]="hello"; //字符数组储存 hello
//字符串常量-->“hello”不许被修改
const char sub1[]="hello";//字符数组储存hello 不允许被修改
const char sub2[]="hello";
//sub1与sub2值相同 都不能修改 内存浪费
//修正
const char* p="hello";//字符串常量“hello”-->内存 数据区 .data
const char* q="hello";
//p,q分别开辟4B(x86)空间 保存数据区内hello的地址,常量在数据区只储存一份
//p,q在同一地址取值
6.数组指针
是一个指针,指向数组类型的指针
int arr[10];
int (*p)[10]=&arr; //p的类型-->指针 int (*)[10]
//p+1--> 偏移量 1*sizeof(*p)B-->40B
int *q=arr;//q的类型-->指针 int*
//q+1--> 偏移量 1*sizeof(*q)-->4B
7.void*无类型指针
int *q=&val;//q+1偏移量4B
void* p;//储存地址 p+1-->无法知道偏移量 void所占字节数
void* 变量名=任意类型地址
注意:
1.不能对void*指针进行算数运算
2.void* p=#不能对void*指针进行解引用
通用操作:
1.void* arr 无类型指针 目的 储存地址 摒弃原生类型
2.const void* brr 遍历
3.逐字节拷贝
8.指针与函数
8.1返回值是指针
局部变量不允许被返回
int *Operate(int a,int b)//局部变量地址禁止返回
{
int arr[]={a+b,a*b};
// 普通局部生存周期函数调用结束销毁
return arr;
}
//err
修改:
1.将 arr 设计为全局变量 所有函数共用一份该变量
int arr[2];
void Operate(int a,int b)//局部变量地址禁止返回
{
arr[0]=a+b;
arr[1]=a*b;
}
//全局变量 所有函数都可以访问并使用
2.修改为 静态局部变量 ----> 变量存活时间main函数结束时(项目结束)该变量内存才会被回收。
存储区域:数据区.data
int *Operate(int a,int b)
{
static int arr[]={a+b,a*b};//可见性在局部
return arr;
}
延长局部变量生存周期 该局部变量前加static
静态局部变量:只被定义一次
8,2形参是指针
8.2.1 形参修改影响实参 必须传递实参的地址,解引用
void ChangeSize(int* psize) psize[0x123]
{
(*pisze)++;
}
int main()
{
int size=10; size 0x123[10]
ChangeSize(&size);
return 0;
}
8.2.2节省空间
void Show(const int*arr,int len){}
void mystrcpy(char*sub,const char*str);
8.3函数指针
int add(int a,int b){}
int mul(int a,int b){}
函数返回值类型 (*p)(形参列表)=函数地址;
函数名:函数入口地址
int (*p)(int,int)=add;
p=mul;
//add(1,2); p(1,2)
练习:
long*fun1();
定义指针 指向fun1并完成函数调用
long *(*p1)()=fun1;
p1(); 调用fun1函数;
void (*signal(int sig, void (*func)(int)))(int);
typedef void (*PFun)(int);
PFun signal(int sig,PFun pfun);
调用:
void func1(int a){如何复制操作 }
void func2(int b){ 如何粘贴操作 }
signal(CTRLC, func1);
signal(CTRLV,func2);
9.str系列函数
9.1.strlen
求字符串长度,返回‘\0’前的字符个数(不含‘\0’)
unsigned int mystrlen(char* str) {
int len = 0;
for (int i = 0; str[i] != '\0'; i++) {
len++;
}
return len;
}
//size_t mystrlen1(const char* str)
//{
// size_t count = 0;
// while (*str != '\0')
// {
// count++;
// str++;
// }
// return count;
//}
9.2. strcpy(char*arr, const char *brr)
将src指向的字符串复制到dest,需保证dest空间足够,会复制'\0'。
void mystrcpy(char* str, char* sub) {
int j = 0;
for (int i = 0; sub[i] != '\0'; i++) {//while(str[j]=sub[i]{
str[j++] = sub[i]; //i++; j++; }
}
str[j] = '\0';
}
void mystrcpy1(char* str, const char* sub)
{
while (*sub != '\0') {
*str = *sub;
str++;
sub++;
}
*str = '\0';
}
void mystrcpy2(char* str, const char* sub)
{
while (*str = *sub) {//[hello\0] sub hello
str++;
sub++;
}
}
9.3. strcat(char *arr, const char *brr)
将src指向的字符串追加到dest末尾,dest需有足够空间,会合并'\0'。
void mystrcat(char* str, char* sub) {
int len1 = mystrlen(str);
int len2 = mystrlen(sub);
int j = 0, i = 0;
for (i = len1; i < len1 + len2; i++) {
str[i] = sub[j++];
}
str[i] = '\0';
}
void mystrcat1(char* str,const char* sub) {
while (*str != '\0') {
str++;
}
while (*sub != '\0') {
*str = *sub;
str++;
sub++;
}
*str = '\0';
}
9.4. strcmp(const char *s1, const char *s2)
比较两字符串,相等返回0;s1>s2返回1;s1<s2返回-1(按ASCII值比较)。
int mystrcmp(char* str, char* sub) {
int i = 0;
int a = 1;
while (str[i] != '\0' && sub[i] != '\0') {
if (str[i] != sub[i]) {
a = 0;
if (str[i] > sub[i]) {
return 1;
}
else {
return -1;
}
}
i++;
}
if (a == 1) {
return 0;
}
}
int mystrcmp1(char* str, char* sub) {
int i = 0;
while (str[i] == sub[i]) {
if (str[i] == '\0') {
return 0;
}
i++;
}
return str[i] > sub[i] ? 1 : -1;
int mystrcmp2(const char* str, const char* sub) {
while (*str != '\0' && *sub != '\0') {
if (*str != *sub) {
if (*str > *sub) {
return 1;
}
else {
return -1;
}
}
str++;
sub++;
}
if (*str != '\0') {
return 1;
}
else if (*sub != '\0') {
return -1;
}
else {
return 0;
}
}
10.mem系列函数 头文件#include<string.h>
10.1.memcpy 内存拷贝
不考虑内存重叠问题使用它前提条件 两个内存独立

10.2.memmove 内存拷贝
考虑内存重叠问题指针判断是否有重叠

11.面试题
1.大小端/大小字节序 --- 数据在内存中的存储模式
小端 : 低地址存储低位数据("滴滴")
int val = 0x12345678;
_0x78__ _0x56__ __0x34__ _0x12__
低地址 高地址
char* p = (char*)&val; 类型强转,只解析一个字节
if( *p == 0x78) 小
else 大
大端: 与小端相反
2. 数组指针 和 指针数组
1) 数组指针 --> 指针 指针+1(偏移量,能力)
2) 指针 数组 --- 数组 每个元素是指针
3) int arr[2]; int(*p)[2]=&arr; 数组指针
const char* p[] = {"zs","lisi"}; 指针数组

11万+

被折叠的 条评论
为什么被折叠?



