目录
指针 + 一维字符型数组:
字符串的储存原理:
char a[20] = "hello";//上述式子表示将字符串装进了字符数组空间中
原理解释:首先编译器先开了一块栈上的内存空间,然后去访问字符串常量空间,
一个个将字符串常量空间里的对应字母的ascii值拿出来放到了开出来的栈的空间之中,
由此实现了用数组存储字符串常量的方式,并可借助字符数组更改数据。(字符串常量区只可读不可写)
两种初始化方法:
char s[] = "hello";//先定义了一个数组装字符串
char *p = s;//再将开在栈空间上字符数组的首地址给了指针s
通过指针访问字符串的另一种方式(访问字符串常量空间)
const char *p = "hello";//后方字符串是一个常量,赋值操作的效果是将字符串常量首地址空间给了指针p(前方加的const标志着指针内的数据只可读不可写)
即*p = 'a'运算是非法的
const关键词:
单词含义:只读
作用:将修饰对象的权限更改为只读。
修饰字符指针的三种形式:(修饰对象不同)
判断修饰对象的原则:
就近原则(const离谁近就修饰谁)
1.const char *s;//1,2两种形式作用等价(const离基类型近,所以限定基类型数据不可更改)
2.char const *s;//const在中间,离指针和基类型一样近,以修饰基类型为主
3.char * const s;//该形式修饰的是指针本身的数据,限定p为只可读,。(const离指针近限定指针S内所存地址不可修改)
可以从三种不同的角度来理解其不同的形式:
以下将从三种角度分析第一种形式:
const int *p
1.操作角度:
上述一二两种形式限定基类型,表示不可以通过间接访问(即*p = ‘a’)的方式修改所指向的数据。
2.从类型角度:
const int *p 与 int *p 所代表的是不同类型的指针
3.权限角度:
const int *p //只能读p所指向的整形数据
int *p //其能读也能写指针指向的数据
重要的注意事项:当带const的指针和不带const的指针涉及到地址赋值时;要注意所修饰指针的权限只可缩小不可扩大。
eg:
const int *p ;
int *p ;
p = q;//把可读写的权限缩小到可写;是合法的形式
q = p;//将只可读的权限阔刀到了可读可写,是不合法的形式。
应用:
应用:
1.如果 不想 通过*p方式改变基类型对应的数据
const int *p = &a;
int const *p = &a;
2.如果 指针变量p 定义好后,不想再指向别的变量则
int * const p = &a;
const 函数在函数调用参数的使用:
举例:
void Puts(char *ch)
char s[10];
如果此时主函数出现了错误代码:
Puts((*s)++);
则字符数组中的数据就被修改掉了。因此为了避免这种现象可以采用以下写法:
void Puts(const char *ch)
其表示传过来的指针限定了基类型,一旦出现修改指针所指向的数据就会发生报错。
使用注意:
形参 设计为 const char *
1.目的:
防止函数中的误操作
2.好处
(1).提前发现问题
将运行时问题,提前到编译时
(2).const char *
可以接收
char *
const char *
实参:
可以 数组名
可以 指针变量 char *p 或const char *p
可以 直接是一个字符串常量
提高参数的适用性
注意:
能写成const的 都写const
指针+字符串:
字符串在c语言中以字符数组的形式存储。
字符串常量——存储在字符串常量区
处理字符串:
指针指向字符串两种形式:
char s[] = "hello"; //表示 在栈上开辟一块空间,用字符串常量中的 "hello"
//进行初始化
const char *p = "hello"; //表示 p指向了 字符串常量区中的 "hello"
//因为 是指向了字符串常量区
//只能做读取操作,不能修改
涉及新函数:
char *Strncpy(char *dest, const char *src, size_t n)//限定长度复制函数
char *Strncat(char *dest, const char *src, size_t n)//限定长度拼接函数
int strncmp(const char *s1, const char *s2, size_t n);//限定长度比较函数
以上函数请自行了解更为详细的博客,此处只做简单提及。
指针 + 二维数组:
回顾二维数组的形式:
int a[2][3]
1.c语言中并不真正存在二维数组
2.二维数组的本质是一维数组的一维数组。
3.二维数组也符合数组的特点。
本质上可写为:
int[3] a[2]
指针如何表示二维数组的两个问题:
1.所要处理的数据是什么类型的?
由于是二维数组,所以其数据类型相当与是一个一维数组
因此可知指针的基类型为:
基类型:int [3]
2.需要定义什么样的指针来表示数组:
确定了基类型,则只需按照类似指针定义方式定义指针就可以推出以下形式:
int [3] *a;//不标准写法,非法
但是c语言不支持这种写法不支持该种写法,所以换为
正确写法为:int (*a)[3];//其就表示二维数组的指针
结合初始化理解:
int b[3][4]
int (*a)[4] = b;//其表示定义了一个一维的指针变量并将二维数组b的首地址给了过去。(个人理解:a代表了整一个二维数组,int[4]就可以知道它每一行的偏移量,然后其a[0]偏移量一块是 int所代表的字节*4)
等价:
*p <=> a[0] // 相当于是内部这个一维数组的数组名,第一行地址(当做外层)
(*p)[0] //指的是第一行第一个位置,将下标运算符扩展,从第一行地址还要进入内层(精准偏移到所指位置)
*(*p+0) //**p
由此可推出一般式子:
*(*(p+1)+1) <=> a[1][1]
*(*(p+i)+j) <=> a[i][j]
散装知识点:
void *memcpy(void *dest, const void *src, size_t n)
{
//一个字节一个字节拷贝
}
void * //NULL 空指针
//空类型的指针 --- 万能指针
//可以接收任意类型的指针
注意:
1.注意,如果用 空类型指针 进行 间接运算
必须 转换成 有明确类型的指针
```