![](https://img.haomeiwen.com/i11218161/1248a28539439d59.png)
1.指针的基础
2. 指针参数,修改值
3. 数组指针
4. 悬空指针和野指针,空指针
5. 函数指针
指针有什么用????
1)可以提高程序的编译效率和执行速度,使程序更加简洁。
(2)通过指针被调用函数可以向调用函数处返回除正常的返回值之外的其他数据,从而实现两者间的双向通信。
(3)利用指针可以实现动态内存分配。
(4)指针还用于表示和实现各种复杂的数据结构,从而为编写出更加高质量的程序奠定基础。
(5)利用指针可以直接操纵内存地址,从而可以完成和汇编语言类似的工作。
(6)更容易实现函数的编写和调用
总结的指针的意义: 通过方法赋值!
得到对象,代码编程中c和java区别.c可以传入对象的地址在方法里面去赋值, java一般通过返回值!
1. 指针为什么要有类型?
指针强化一个指针的大小始终是32位系统占4个字节,64位系统占8字节
1. 因为指针取值的时候要知道怎么取!
2. 指针偏移, 需要知道占用多少个字节!
指针为什么要有类型:
为了地址增量的方便:例如double型的地址增量为8,而int型指针的地址增量为4
为了类型安全:帮助编译器发现你是否用了错误的类型
指针是以内存地址作为变量地址
参考博客:
https://www.runoob.com/cprogramming/c-pointer-to-pointer.html
不同类型的指针的写法:
struct Books *book;
int *ptr;
在变量前面加*,别人就知道是指针!
指针可以多次指向不同的地址
举例:
Boxbox2;
box2.height=2.0;
Box*box2point;
box2point=&box2;
cout<<"指针指向二: "<<box2point->height<<endl;=
box2point=&box1;
cout<<"指针指向一: "<<box2point->height<<endl;
指针最基础的用法:
得到变量的地址: 取址符号
#include<iostream>
usingnamespacestd;
intmain()
{
intvar=20;// 实际变量的声明
int*ip;// 指针变量的声明
ip=&var;// 在指针变量中存储 var 的地址
cout<<"Value of var variable: ";
cout<<var<<endl;
// 输出在指针变量中存储的地址
cout<<"Address stored in ip variable: ";
cout<<ip<<endl;
// 访问指针中地址的值
cout<<"Value of *ip variable: ";
cout<<*ip<<endl;
// 对一个变量取*
cout<<"Value of *var variable: ";
cout<<*var<<endl;
return0;
}
当上面的代码被编译和执行时,它会产生下列结果
Valueofvarvariable:20
Addressstoredinipvariable:0xbfc601ac
Valueof*ipvariable:20
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址!
var是变量! &var是变量的地址. *ip是int类型的指针. ip = &var; // 在指针变量中存储 var 的地址
*ip: 对指针取值: 20.
1.地址和指针
指针
变量100
打印它的值, 它的地址&
地址的值:* &100
指针的使用举例:
int i =20;
int *p = &i;// 获取i的地址,其实p也是一个变量,是指针变量
*p: 用来存放变了变量的地址!
*:有两个作用:
i.用于定义一个指针:type*var_name;,var_name是一个指针变量,如int*p;
ii.用于对一个指针取内容:*var_name,如*p的值是1。
4. Null 指针
#include<iostream>
usingnamespacestd;
intmain()
{
int*ptr=NULL;
cout<<"ptr 的值是 "<<ptr;
return0;
}
ptr的值是0
Null指针的值是0 (应该是地址是0)
如果对它取值会怎么样?
cout << "*ip:";
cout << *ip << endl;
野指针:指 释放了指针对应的内存地址后,没有把指针置为 NULL
NULL : NULL 相当于指向 0x00000000,这块地方是 c 和 c++ 编译器所持有的,不能在这块区域赋值
仅仅通过非空判断是不行的, 必须要把地址至为空,
int main(){
// 写入位置 0x00000000 时发生访问冲突
char* p1 = NULL; // p1 = NULL,NUll 也是地方,指针指向 NULL 相当于指向 0x00000000
// 但是我们不能对 0x00000000 去操作,这块地方是 c 和 c++ 编译器所持有的
// Student student = null; 不用纠结 null 是啥,跟 c 和 c++ 有点类似
strcpy(p1,"1122"); // 把 1122 赋值给p1 NUll的位置,这是错误的
printf("p1 = %s",p1); // Null的地址不能操作
getchar();
}
2. 指针修改值 (值传递和指针传递)!
java中,基本数据类型不能修改值,值传递和指针传递!
但是c中,可以通过修改地址中的值,修改基本数据类型的值
变量赋值的办法
1.直接赋值
2.通过指针间接赋值
指针的重要应用: 就是给变量赋值
编程demo: 2个数交换
题目:
int a=10
int b=20
int *p1=&a;
int *p2=&b;
p1=p2;
这个是什么意思: p1和p2是一个变量, 把p2的值给了p1. 但是a和b的地址都没有变!
面试题: 2个int类型数据交换!
升级:不采用额外的空间,2个int类型的数据进行交互.
解答:不能直接,交互,以前是数组可以交互.
需要通过地址或者传递yin yong
int main ()
{
int var =20; /* 实际变量的声明 */
int *ip; /* 指针变量的声明 */
ip = &var; /* 在指针变量中存储 var 的地址 */
printf("var 变量的地址: %p\n", &var );
/* 在指针变量中存储的地址 */
printf("ip 变量存储的地址: %p\n", ip );
/* 使用指针访问值 */
printf("*ip 变量的值: %d\n", *ip );
return 0;
}
var 变量的地址: 0x7ffeeef168d8ip 变量存储的地址: 0x7ffeeef168d8*ip 变量的值: 20
3.数组指针
26、若数组名作实参而指针变量作形参,函数调用实参传给形参的是?
A、数组的长度 B.数组第一个元素的值
C、数组所有元素的值
D、数组第一个元素的地址
【标准答案】D
https://blog.csdn.net/lirendada/article/details/122931987
34、为什么数组名作为参数,会改变数组的内容,而其它类型如int却不会改变变量的值?
【参考答案】
当数组名作为参数时,传递的实际上是地址。
而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调函数内部对形参的改变并不影响实参的值。
总结:数组指针指向的是数组的首地址
数组的遍历和其他语言写法区别!
int main() {
int a[3] = {1,2,3};
int (*p)[3] = a;//compile warning: initialization from incompatible pointer type
printf("%p,%p,%p,%p,%d,%d\n",a,&a,p,*p,**p,*p[0]);
return 0;
}
a的值==*p(数组取地址的值 )==p0的值========首地址
总结:
1.数组的值==数组取*的值==数组第一个元素的值
写法注意: 因为他们3个相等!
2. 所以数组的指针没有int *[]这种写法, 都是通过int *
int main ()
{
int var[MAX] ={10,100,200};
int *ptr;
// 数组指针的存放,用这种
ptr=var;
for(int i=0;i<MAX;i++){
// 不需要额外赋值
// *ptr=var[i];
cout << "地址[" << i << "] = ";
cout << ptr << endl;
cout << "值:[" << i << "] = ";
cout << *ptr << endl;
ptr++;
}
return 0;
}
3.数组参数传递(特别注意)
组作为参数传递时获取不到长度的问题!!
原因:数组作为参数传递,会退化成为一个指针,传递的是首地址 (高效)
所以我么使用的时候, 传递指针,同时传递数组的长度,这样才能变量
数组指针移动的时候要注意是否越界了, 访问到系统其他的内存去了!
不想java通过数组的长度判断!
int* arr_a=a; 结果: 相当于:*&a =====对地址取值得到1
分析:
p是一个指向数组的指针(这里的p只不过是指针变量的名字,说p指向一个数组,其实就是p变量保存了数组的首地址)那么,在上面的例子中我们把 a 数组的地址给了这个指针变量(注意:&a取得是整个数组的地址)所以p指向了这个数组,p的值是数组首字节的地址。
指针数组循环赋值: (常用:数组值的填充)
通过观察可以发现: 数组的内存地址是连续的!
比较重要的demo: 数组, 通过指针循环赋值
arr[i+i]=* arr[i]
int main ()
{
int var[MAX] = {10, 100, 200};
for (int i = 0; i < MAX; i++)
{
*var = i; // 这是正确的语法
cout << "var[" << i << "]的内存地址为 ";
// 把数组的值直接改变了
cout << *var << endl;
}
return 0;
}
结果:
var[0]的内存地址为 0
var[1]的内存地址为 1
var[2]的内存地址为 2
指针移动和指针比较:
指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的
然而,指针和数组并不是完全互换的
数组指针: 指针指数组的第一个元素的地址
数组的for循环遍历正确的写法: 否则在linux下会报错!
for(; i < 5; i++)
5. 函数指针: 当回调用,可以方法里面传入方法!和kotlin一样
把一个方法指针作为参数传递
举例: 下载文件的时候,把进度回调给调用方
void operate(void (method)(int, int), int num1, int num2) {
method(num1, num2);
}
void add(int num1, int num2) {
num1 + num2;
}
int main() {
add(1, 2);
operate(add, 1, 2);
}
函数指针的定义: void(method) (int,int )
案例二:
void print(char *message) {
print(message);
}
void method(void(*print_m)(char *)) {
print("函数指针调用");
}
int main() {
add(1, 2);
operate(add, 1, 2);
void (*print_m)(char *) =print;
method(print);
}
https://blog.csdn.net/q925092273/article/details/109294867?spm=1001.2014.3001.5502
c 和 java 的方法不同所在,c 可以传对象的地址在方法里面去赋值,java 一般都是通过返回值c的返回值一般是告诉你错误码!
6.多级指针 (用的少)
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
int i =20;
int *p = &i;// 获取i的地址,其实p也是一个变量,是指针变量
LOGD("x=%d", i); // 值
LOGD("x=%p", p); // 地址
LOGD("指针取值%d", *p);
int **p2 = &p;// 获取p指针变量的地址
// 取p2的值
LOGD("取一个星x=%p", *p2); // p的值==i的地址
LOGD("取2个星x=%d", **p2); // i的值
2022-10-12 20:21:20.661 18797-18797/com.yuedong.ndkmap D/System.out.c: x=20
2022-10-12 20:21:20.661 18797-18797/com.yuedong.ndkmap D/System.out.c: x=0x7ff7d37dfc
2022-10-12 20:21:20.661 18797-18797/com.yuedong.ndkmap D/System.out.c: 指针取值20
2022-10-12 20:21:20.661 18797-18797/com.yuedong.ndkmap D/System.out.c: 取一个星x=0x7ff7d37dfc
2022-10-12 20:21:20.661 18797-18797/com.yuedong.ndkmap D/System.out.c: 取2个星x=20
网友评论