C++指针笔记

21 篇文章 0 订阅

为什么要使用指针

1.函数的值传递,无法通过调用函数,来修改函数的实参.
2.被调用函数需要提供更多的“返回值”给调用函数
3.减少值传递时带来的额外开销,提高代码执行效率

指针是什么

#include <stdio.h> 
#include <stdlib.h>
int main(void){
	int age; 
	char ch;
//定义了一个指针
//指针本身也是一个变量
//名称是 p, 它是一个指针,可以指向一个整数
//也就是说: p 的值就是一个整数的地址!!!
	int *p ; 
	char * c;
//指针 p 指向了 age 
//p 的值,就是 age 的地址 p = &age; c = &ch;
//scanf_s("%d", &age);
	scanf_s("%d", p);
	printf("age: %d\n", age);
	system("pause"); 
	return 0; 
   }

指针的定义

int *p;  int *p1, *p2;
或者
int* p;  int* p1,p2; //p1 是指针, p2 只是整形变量
或者
int * p; 
或者
int*p;//不建议

注意:
32 位系统中,int 整数占 4 个字节,指针同样占 4 个字节
64 位系统中,int 整数占 4 个字节,指针同样占 8 个字节

空指针和坏指针

#include <stdio.h> 
#include <stdlib.h>
	int main(void){ 
		int room1 = 666; 
		int room2 = 888;
		
		int girl ; 
		int *select ;
		scanf_s("%d", &girl);
		if(girl == 666){
			select = &room1;
		}else if(girl == 888){
			select = &room2;
		}
		printf("选择的房间是: %d\n", *select); 
		system("pause");
		return 0; 
 }

什么是空指针?

空指针,就是值为 0 的指针。(任何程序数据都不会
存储在地址为 0 的内存块中,它是被操作系 统预留的内存块。)
int *p = 0; 
或者
int *p = NULL; //强烈推荐
空指针的使用
指针初始化为空指针 
int *select = NULL; 
目的就是,避免访问非法数据。
指针不再使用时,可以设置为空指针

表示这个指针还没有具体的指向,使用前进行合法性判断
int *p = NULL;
if (p) { //p 等同于 p!=NULL
//指针不为空,对指针进行操作
}

坏指针

int *select; //没有初始化
情形一
printf(“选择的房间是: %d\n”, *select);
情形二
select = 100;
printf(“选择的房间是: %d\n”, *select);

const

总结: 看 const 离类型(int)近,还是离指针变量名近,离谁近,就修饰谁,谁就 不能变

指针的算术运算

.总结: p++ 的概念是在 p 当前地址的基础上 ,自增 p 对应类型的大小, 也就是说 p = p+ 1*(sizeof(类型))
比如定义的int 类型的指针,那么指针加1,编译器会自动加四个字节

知识点

指针与整数的运算,指针加减数字表示的意义是指针在数组中位置的移动;
对于整数部分而言,它代表的是一个元素,对于不同的数据类型,其数组的元素占 用的字节是不一样的,
比如指针 + 1,并不是在指针地址的基础之上加 1 个地址,而是在这个指针地址的 基础上加 1 个元素占用的字节数:

如果指针的类型是 char*,那么这个时候 1 代表 1 个字节地址;
如果指针的类型是 int*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 float*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 double*,那么这个时候 1 通用公式:
数据类型 *p;
p + n 实际指向的地址:p 基地址 + n * sizeof(数据类型)
p - n 实际指向的地址:p 基地址 - n * sizeof(数据类型)
比如
(1)对于 int 类型,比如 p 指向 0x0061FF14,则:
p+1 实际指向的是 0x0061FF18,与 p 指向的内存地址相差 4 个字节
p+2 实际指向的是 0x0061FF1C,与 p 指向的内存地址相差 8 个字节
(2)对于 char 类型,比如 p 指向 0x0061FF28,则:
p+1 实际指向的是 0x0061FF29,与 p 指向的内存地址相差 1 个字节;
p+1 实际指向的是 0x0061FF2A,与 p 指向的内存地址相差 2 个字节;
(1)指针和指针可以做减法操作,但不适合做加法运算;
(2)指针和指针做减法适用的场合:两个指针都指向同一个数组,相减结果
为两个指针之 间的元素数目,而不是两个指针之间相差的字节数
比如:

int int_array[4] = {12, 34, 56, 78};
int *p_int1 = &int_array[0]; 
int *p_int2 = &int_array[3];
p_int2 - p_int1 的结果为 3,即是两个之间之间的元素数目为 3 个。

如果两个指针不是指向同一个数组,它们相减就没有意义。
(3)不同类型的指针不允许相减,
比如
char *p1;
int *p2; p2-p1 ;
是没有意义的

二级指针

二级指针也是一个普通的指针变量,只是它里面保存的值是另外一个一级指针的地址
定义:
int guizi1 = 888;
int *guizi2 = &guizi1; //1 级指针,保存 guizi1 的地址
int **liujian = &guizi2; //2 级指针,保存 guizi2 的地址,guizi2 本身是一个一级指针变量
用途:

  1. 二级指针的用途: 1. 普通指针可以将变量通过参数“带入”函数内部,但没办法将内部变量“带出”函数,数据结构经常会使用二级指针
  2. 二级指针可以不但可以将变量通过参数函数内部,也可以将函数内部变量 “带出”到函 数外部。
    可以定义多级指针指向次一级指针
    比如:
    int guizi1 = 888;
    int *guizi2 = &guizi1; //普通指针
    int **guizi3 = &guizi2; //二级指向一级
    int ***guizi4 = &guizi3; //三级指向二级
    int ****guizi5 = &guizi4; //四级指向三级

指针表示法和数组表示法

数组完全可以使用指针来访问, days[3] 和 *(days+3) 等同

#include <stdio.h> 
#include <stdlib.h>
	int main(void) { 
	int days[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 
	int index = 0;
	 for (index = 0; index < 12; index++){ 
	 //数组表示法 
	 printf("Month %2d has %d days.\n", index+1, days[index]);
	  //指针表示法 
 	 printf("Month %2d has %d days.\n", index+1, *days+index); }
 	 print_months1(days, 6); 
     //print_months2(days, 12); 
 	 system("pause");
  	 return 0; 
  }

指向数组的指针

int (*p)[3]; //定义一个指向三个成员的数组的指针
访问元素的两种方式:
数组法: (*p)[j]
指针法: *((*p)+j)
使用普通指针访问二维数组
int A[4][3];
int *p; //定义一个指针
p = A[0];
或者
p=&A[0][0];

数组与指针的区别

数组:数组是用于储存多个相同类型数据的集合。
指针:指针是一个变量,但是它和普通变量不一样,它存放的是其它变量在内存中的地址。
.1. 赋值
数组:只能一个一个元素的赋值或拷贝
指针:指针变量可以相互赋值
2. 表示范围
数组有效范围就是其空间的范围,数组名使用下表引用元素,不能指向别的数组
指针可以指向任何地址,但是不能随意访问,必须依附在变量有效范围之内
3. sizeof
数组:
数组所占存储空间的内存:sizeof(数组名)
数组的大小:sizeof(数组名)/sizeof(数据类型)
指针:
在 32 位平台下,无论指针的类型是什么,sizeof(指针名)都是 4.
在 64 位平台下,无论指针的类型是什么,sizeof(指针名)都是 8.

指针数组和数组指针(重点)

 针指数组:
 int *qishou[2];//定义一个有两个元素的指针数组,每个元素都是一个指针变量 
 int girl1= 167;
  int girl2 = 171;
   qishou[0] = &girl1; 
   qishou[1] = &girl2;
   数组指针:
    int (*p)[3]; //定义一个指向三个成员的数组的指针 
    访问元素的两种方式: 
    int A[4][3]={{173, 158, 166},
  			    {168, 155, 171},
  			    {163, 164, 165},
  			    {163, 164, 172}}; 
    		    p = &A[0]; 
       			数组法: (*p)[j]
       			指针法: *((*p)+j)

传参
数组传参时,会退化为指针!
(1)退化的意义:C 语言只会以值拷贝的方式传递参数,参数传递时,如果只拷贝整个数 组,效率会大大降低,并且在参数位于栈上,太大的数组拷贝将会导致栈溢出。
(2)因此,C 语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时,将数组名 看做常量指针,传数组首元素的地址。

void 类型指针

void => 空类型
void* => 空类型指针,只存储地址的值,丢失类型,无法访问,要访问其值,我们必须对这个指 针做出正确的类型转换,然后再间接引用指针。
所有其它类型的指针都可以隐式自动转换成 void 类型指针,反之需要强制转换

#include <stdio.h> 
#include <stdlib.h>

	int main(void){ 
		int arr[]={1, 2, 3, 4, 5}; 
		char ch = 'a'; 
		void *p = arr;//定义了一个void 类型的指针 
		//p++; //不可以, void * 指针不允许进行算术运算 
		p = &ch; //其它类型可以自动转换成void * 指针 
		//printf("数组第一个元素: %d\n", *p); //不可以进行访问 
		printf("p: 0x%p ch: 0x%p\n", p, &ch); 
		//强制类型转化
		char * p1 = (char *)p; 
		printf("p1 指向的字符是: %c\n", *p1); 
		system("pause");
 return 0;
  }

函数指针以及void指针的用法 qsort函数

#include <iostream>
#include <Windows.h>
#include <string>

using namespace std;

int compare_int(const void* a, const void* b) {
	//cout << "**调用compare_int函数**" << endl;
	int* a1 = (int*)a;
	int* b1 = (int*)b;

	return *a1 - *b1;
}

int compare_char(const void* a, const void* b) {
	//cout << "**调用compare_char函数**" << endl;
	char c1 = *((char*)a);
	char c2 = *((char*)b);

	
	if (c1 >= 'A' && c1 <= 'Z')c1 += 32;
	if (c2 >= 'A' && c2 <= 'Z')c2 += 32;

	return c1 - c2;
}

int main(void) {
	int x = 10;
	int y = 20;
	int sun = NULL;

	//函数地址
	printf("compare_int的地址:0x%p\n", &compare_int);
	//sun=compare_int(&x, &y);
	//cout << sun << endl;

	//函数指针的定义 把函数声明移过来,把函数名改成(* 函数指针名)
	int (*fp)(const void*, const void*);
	fp = &compare_int;	//把函数的地址赋值到函数指针
	//两种调用方式
	//(*fp)(&x, &y);	//第一种
	//fp(&x, &y);	//第二种


	//qsort函数 对整形数组排序
	int arr[] = { 2,10,0,1,11,8,7,111,520 };
	qsort(arr, sizeof(arr) / sizeof(int)-1, sizeof(int), &compare_int);

	cout << "数组排序:";
	for (int i = NULL; i < sizeof(arr) / sizeof(int); i++) {
		printf("%d\t", arr[i]);
	}
	cout << endl;

	//qsort 可以对任何类型的数组进行排序
	char arr1[] = { "abcdefghiABCDEFGHI" };
	qsort(arr1, sizeof(arr1) / sizeof(char)-1, sizeof(char), &compare_char);
	//这两个-1是因为从0开始计算带的,没必要多计算一个
	cout << "字符串排序:";
	for (int i = NULL; i < sizeof(arr1) / sizeof(char)-1; i++) {
		printf("%c   ", arr1[i]);
	}
	cout << endl;

	system("pause");
	return 0;
}

在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值