[C/C++]指针用法带示例详解

一.空指针

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

int main(){
	char ch = 'a';
	void *p=&ch;

	//p++;×
	//无法进行算术运算
	//不知加几(32位机下int型加4个字节,char型加1个字节)

	//printf("*p=0x%d",*p);×
	//无法访问

	printf("p=0x%d,&ch=0x%d\n",p,&ch);//可存储地址

	//强制类型转换
	char *p1=(char *)p;
	printf("*p1=%c",*p1);
}

二.指针与数组

指针与一维数组

#include <stdio.h>
#include <Windows.h>
/* 使用指针打印数组元素 */
void print(int* num, int n) {//√函数中指定打印个数/长度
	for (int i = 0; i < n; i++)
		printf("第%2d个数字为:%2d\n", i + 1, num[i]);//num[i]为指针数组打印
}

int main() {
	int num[] = { 1,2,3,4,5,6,7,8,9,10 };
	int len1 = sizeof(num) / sizeof(num[0]);
	int* p1 = num;

	//p=&num;×
	//p1=num;√指针默认指向数组首地址,故无需提及其地址
	for (int i = 0; i < len1; i++) {
		printf("手指掰的第%d个数字为%d=%d,地址为%p\n", i + 1, num[i], *(p1), p1);//num[i]为数组打印,*(p1)为指针打印
		p1++;//p=p+sizeof(int);
	}

	printf("---------------------------");

	char alp[] = { 'a','b','c' };
	int len2 = sizeof(alp) / sizeof(alp[0]);
	char* p2 = alp;
	for (int i = 0; i < len2; i++) {
		printf("手指比划的第%d个字母为%c,地址为%p\n", i + 1, alp[i], p2);
		p2++;//p=p+sizeof(int);
	}

	printf("---------------------------");

	print(num, 10);

	system("pause");
	return 0;
}

指针与二维数组

#include <stdio.h> 
#include <stdlib.h>//含system

//选取二维女兵方阵中最高的两位的身高作为旗手,分别存在flagBearer[0]和flagBearer[1]
int main(void) {
	int girls[4][3] = { {173, 158, 166},
	{168, 155, 171},
	{163, 164, 165},
	{163, 164, 172} };
	int* flagBearer[2];//top2

	//初始化
	if (girls[0][0] > girls[0][1]) {
		flagBearer[0] = &girls[0][0];
		flagBearer[1] = &girls[0][1];
	}
	else {
		flagBearer[0] = &girls[0][1];
		flagBearer[1] = &girls[0][0];
	}

	//选取最高的两位
	for (int i = 2; i < 12; i++) {
		if (*flagBearer[1] >= girls[i / 3][i % 3]) {
			continue;
		}
		if (girls[i / 3][i % 3] <= *flagBearer[0]) {
			flagBearer[1] = &girls[i / 3][i % 3];
		}
		else {
			flagBearer[1] = flagBearer[0]; flagBearer[0] = &girls[i / 3][i % 3];
		}
	}
	printf("最高女兵的身高: %d , 次高女兵的身高: %d\n", *flagBearer[0], *flagBearer[1]);
	system("pause");
	return 0;
}

指针与多维数组

第三维相当于页
具体用法省略

三.指针使用常见错误

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

int main() {

	//①未初始化
	//赋值前调取指针内容报错
	//int *p;×
	//printf("p=%p",p);×-The variable 'p' is being used without being initialized.中断或胡乱显示地址为0xCCCCCCCC
	int* p = NULL;
	printf("p=%p\n", p);//p=00000000;赋值前也不会报错

	//②指向内容未取地址&
	//pp=x;×-error:不能将int类型值赋给int *类型
	int* pp;
	int x = 10;
	pp = &x;
	printf("pp=%p *pp=%d\n", pp, *pp);

	//③赋值时解引指向内容
	/*int *ppp = NULL;
	//int *ppp;×-The variable 'p' is being used without being initialized.
	int xx = 100;
	*ppp = xx;× 0x00c01648 处有未经处理的异常: 0xC0000005: 写入位置 0xcccccccc 时发生访问冲突
	printf("ppp=%p", ppp);*/

	//④未解引
	//比较数组成员的大小
	/*char input[64];
	scanf_s(input,64);
	char *p1 = &input[0];
	char *p2 = &input[1];
	//if (p1 > p2){×
	if (*p1 > *p2){
		printf("p1>p2");
	}else printf("p1<=p2");*/

	//⑤未更新内容
	//将输入字符串加上空格后打印出来
	char in[64];
	char* p5 = NULL;
	do {
		//scanf_s(in,64);遇空白符停止
		gets(in);//遇回车符停止
		p5 = in;
		while (*p5) printf("%c ", *p5++);
		//}while(*p5!="done");×-指针不能与字符串常量比较
		//}while(strcmp(*p5,"done"));×
	} while (strcmp(in, "done"));//先do再判断,所以仅输入done会加上空格打印一遍

	system("pause");
	return 0;
}

四.常指针

const在int * 中插空摆放可能性:

一个const:3种可能 const int * int const * int * const

两个const:(仅演示)1种可能 const int * const

在一个const摆放基础上, 有4个空, 其中有2个空与const相邻舍去, 故有2个空, 同时2种摆放位置重合舍去, 故共有4个空, const摆放无向后之分, 故再除以2!, 总共计算公式为3 * (4 - 2) / 2! = 3 共三种可能const int * const const int const * int const * const其中const int const * = const int * = int const * , const int * const = int const * const, 故仅演示以上可能

#include <stdio.h>
#include <Windows.h>

int main(){
	int wife=24;
	int girl=18;

	//①渣男-可换可改
	//int wifes[3];
	//int *bad=wifes;
	int *bad=&wife;//指针初始化int型的地址,数组int xx[]型的xx即首地址
	*bad=25;
	printf("老婆年龄:%d;",wife);
	bad=&girl;
	*bad=19;
	printf("女孩年龄:%d\n",girl);

	//②直男-可换不可改
	//=int const *straight=&wife;
	const int *straight=&wife;
	//*straight=26;×
	printf("老婆年龄:%d;",*straight);
	straight=&girl;
	//*straight=20;×
	printf("女孩年龄:%d\n",*straight);

	//③暖男-不可换可改
	int * const good=&wife;
	*good=26;
	printf("老婆年龄:%d;",wife);
	//good=&girl;×
	printf("女孩年龄:%d\n",girl);

	//④超级暖男-不可换不可改
	const int * const great=&wife;
	//*great=30;×
	printf("老婆年龄:%d;",wife);
	//great=&girl;错
	printf("女孩年龄:%d\n",girl);

	system("pause");
	return 0;
}

五.函数指针

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

int compare_int(const void* a, const void* b) {//qsort要求参数必须为const void*型
	//printf("调用compare_int函数了哼唧唧\n");
	int* a_i = (int*)a;
	int* b_i = (int*)b;

	//return *b_i-*a_i;从大到小排
	return *a_i - *b_i;//解引取出导向的整型值,从小到大排
}

int compare_char(const void* a, const void* b) {//qsort要求返回值类型必须为int,故必须将char数组按内容调取,不能按char指针
	char a_c = *((char*)a);//因后续操作全部为解引后值,故定义时即解引
	char b_c = *((char*)b);

	if (a_c >= 'A' && a_c <= 'Z') a_c += 32;
	if (b_c >= 'A' && b_c <= 'Z') b_c += 32;

	return a_c - b_c;
}
typedef int (*Fp) (const void* a, const void* b);
int main() {
	int x = 10, y = 20;
	compare_int(&x, &y);

	//函数的地址
	printf("函数的地址为:0x%p\n", compare_int);

	//函数指针
	//int (*fp) (const void* a, const void* b);//记得(*fp),像指针导向数组一样,解引式调用
	Fp fp = &compare_int;
	fp(&x, &y);

	//对整型数组排序
	int arr[] = { 2, 10, 30, 1, 11, 8, 7, 111, 520 };
	qsort(arr, sizeof(arr) / sizeof(int), sizeof(int), fp);
	//打印
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");

	//将char型字母不分大小写顺序排列(不改变原序列)
	//abcdefghiABCDEFGHI->aAbBcCdDeEfFgGhHIi
	char ch[] = { "abcdefghiABCDEFGHI" };
	qsort(ch, sizeof(ch) / sizeof(char) - 1, sizeof(char), &compare_char);//size_numberOfElements中因为char型最后一个存储的是\0字符串结束符,不对它排序,故-1
	for (int i = 0; i < sizeof(ch) / sizeof(char) - 1; i++) {
		printf("%c", ch[i]);
	}

	return 0;
}

六.指针数组

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

//---一维数组传参---
void method_1(int arr[], int n) {//√含数组长度;为节省空间,arr[]相当于传递首地址指针,即int *arr
	for (int i = 0; i < n; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

//---指针数组传参---
void method_2(int* arr[], int n) {//√含数组长度;为节省空间,*arr[]相当于传递首地址指针,即int **arr
	for (int i = 0; i < n; i++) {
		printf("%d ", *arr[i]);//*(*(arr+i))
	}
	printf("\n");
}

int main() {
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };//数组

	//挨个赋地址值至指针数组
	int* arr_p[10];
	for (int i = 0; i < 10; i++) {
		arr_p[i] = &arr[i];
	}
	method_1(arr, 10);
	method_2(arr_p, 10);

	system("pause");
	return 0;
}

七.数组指针

#include <stdio.h> 
#include <stdlib.h>
/*据同学们报告,A 栋学生楼有学生用高倍望眼镜偷看别人洗澡,
  宿管办领导决定逐个宿舍排查,得到的线报是 A0 到 A3 宿舍的
  某个子最矮的男生。*/
int main() {
	int A[4][3] = { {173, 158, 166},
	{168, 155, 171},
	{163, 164, 165},
	{163, 164, 172} };

	//int *p[3];指针数组:数组,由指针修饰,即数组的所有元素都是指针类型
	int(*p)[3];//数组指针:指针,由数组修饰,即指向数组成员首地址的指针≠指针数组
	// (*p)[0] = &A[0];
	// (*p)[1] = &A[1];
	// (*p)[2] = &A[2];
	
	p = &A[0];
	/*①数组下标法
	for (int i=0;i<4;i++){//i为行数,即宿舍号
		for (int j=0;j<3;j++){
			printf("%d ",(*p)[j]);
		}
		printf("\n");
		p++;//A[0]->A[1]
	}*/

	//指针法
	int* boy;

	//=boy=(*p);
	boy = &(*p)[0];
	for (int r = 0; r < 4; r++) {//r-row行
		for (int c = 0; c < 3; c++) {//c-column列
			printf("%d ", *((*p) + c));
			if (*((*p) + c) < *boy) {
				boy = (*p) + c;//(*p)+j默认为地址
			}
		}
		printf("\n");
		p++;//A[0]->A[1],A[1]->A[2]
	}
	printf("偷窥的男生为:%d\n", *boy);

	return 0;
}

八.指针与引用

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

//①指针
void swap_p(int *a, int *b){//p-pointer
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//②引用
void swap_q(int &a, int &b){//q-quote
	int tmp = a;
	a = b;
	b = tmp;
}

//③只指一数常量指针==②
void swap_cp(int * const a, int * const b){//cp-constant pointer
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int main(){
	int x = 10, &h = x, y = 100;
	//指针与引用的比较
	swap_p(&x, &y);
	printf("x=%d y=%d\n", x, y);
	swap_q(x, y);
	printf("x=%d y=%d\n", x, y);
	swap_cp(&x, &y);
	printf("x=%d y=%d\n", x, y);

	//引用与原量:地址完全相同,相当于别名
	int &z = x;//定义时必须初始化
	printf("&z=%d &x=%d &y=%d\n", &z, &x, &y);//&y-&x=24;初始化紧邻时&y-&x=12;=>引用占用空间

	//&h = y;×
	//可一对多别名,不可多别名对一
	int &a = y, &b = y, &c = y;
	printf("a=%d b=%d c=%d\n", a, b, c);//a=b=c
	printf("&a=%d &b=%d &c=%d\n", &a, &b, &c);//&a=&b=&c

	//常引用-只读
	//①常引用变量
	int f=11;
	const int &e=f;
	//e=12;×
	//不可修改
	//②常引用常量
	const int g=1;
	const int &xx=1;
	//xx = 2;×
	printf("xx=%d",xx);

	system("pause");
	return 0;
}

九.结构体指针

1

#include <iostream>
#include <time.h>//time_t及time所需头文件
using namespace std;

struct _hero_stat{
	int blood;
	int power;
	int level;
	char name[64];
};

void update_1(struct _hero_stat *hero,int type){
	hero->level++;
	switch (type){
		//肉食系:攻击力强且难以被捕获
	case 1:
		hero->blood += 100;
		hero->power += 100;
		break;
		//草食系:攻击力弱且易被捕获
	case 2:
		hero->blood += 10;
		hero->power += 10;
		break;
	default:
		break;
	}
}

int main(){
	struct _hero_stat larry;
	strcpy(larry.name, "Meaty");

	larry. blood = 100;
	larry. power = 100;
	larry. level = 1;

	time_t start, end;
	time(&start); //自1970->1->1开始计时,单位:s
	for (int i = 0; i < 100000000; i++){
		update_1(&larry, 1); //指针:代地址
	}
	time(&end);

	cout<<"Meaty's power="<<larry.power<<endl;
	cout<<"using "<<end-start<<"s"<<endl;//3s

	system("pause");
	return 0;
}

2

#include <iostream>
//指向结构体的指针 *myBoy

struct _boy{//结构体命名习惯:前加_
	char name[32];
	char gender;//m-male f-female
	int age;
}larry;//直接在结构体尾定义属于此结构体的名字

int main5(){
	larry.age = 21;
	larry.gender = 'm';
	printf("larry's age=%d larry's gender=%c\n", larry.age, larry.gender);
	printf("larry's age=%d larry's gender=%s\n", larry.age, larry.gender=='m'?"男":"女");//因判断后输出中文,中文的格式为string

	//指针访问结构体变量成员
	struct _boy * myBoy = &larry;

	//①解引后=larry
	printf("larry's age=%d larry's gender=%s\n", (*myBoy).age, (*myBoy).gender=='m'?"男":"女");

	//②指针直接=larry
	printf("larry's age=%d larry's gender=%s\n", myBoy->age, myBoy->gender=='m'?"男":"女");

	system("pause");
	return 0;
}

十.附基本用法

C语言中指针存储地址的打印与使用:

#include <stdio.h>
int main() {
	int room = 2;//普通房的生物数量
	int dogRoom = 3;//含狗的房的生物数量

	int* larry, * jessica, * coco;
	larry = &room;
	jessica = &room;
	coco = &dogRoom;

	printf("jessica lives in %d\n", &room);//十进制decimal表示
	printf("larry knows he lives in %d\n", larry);//d为十进制整数×

	printf("\ncoco doesn't know it lives in 0x%p\n", coco);//p为用pointer指针表示,0x为强调为十六进制数
	printf("coco doesn't know it lives in 0x%x\n", coco);//%x为用16进制小写字母表示
	printf("coco doesn't know it lives in 0x%X\n", coco);//%X为用16进制大写字母表示

	printf("jessica and larry know they %d live together\n", *jessica);
	*larry = 3;//修改larry=&room中*larry指针所指变量room内容
	printf("but larry wish they %d live together\n", room);

}

不同平台(64位,32位)下指针大小:

#include <iostream>
using namespace std;
int main(){
	int room=2;//大床房

	int *larry,*jessica;
	larry=&room;
	jessica=&room;

	cout<<"房间的位置为:"<<&room<<endl;
	cout<<"larry知道的房间位置为:"<<larry<<endl;
	cout<<"jessica知道的房间位置为:"<<jessica<<endl;

	//因选用活动平台为Win32,32个字=4个字节
	//在Linux64位系统中指针占8个字节
	cout<<"房间的大小为:"<<sizeof(room)<<endl;//4
	cout<<"larry脑袋的大小为:"<<sizeof(larry)<<endl;//4
	cout<<"jessica脑袋的大小为:"<<sizeof(jessica)+sizeof(larry)<<endl;//8
}

空指针或坏指针:

#include <stdio.h>
#include <Windows.h>

int main11(){
	int room;
	printf("请输入房间人数:");
	scanf_s("%d",&room);//取房间人数,而不是房间人数存在旅馆柜子的位置

	//int *select=0;×
	int *select=NULL;//√将数组初始化为0,即select=0;也可

	if (room==2){

		//select=100;没有将定义某变量的位置赋给指针-坏指针
		select=&room;

		printf("肉肉请进呢,一起愉快地度过我们的%d人时光吧\n",*select);
	}else if (room==3){
		select=&room;
		printf("才不要和你玩%dp\n",*select);
	}
	
	if (select==0){//注意是select==0,不是*select,因*select为0不能取到这个地址会发生中断
		printf("同志,你说的房间人数不对啊\n");
	}
	
	system("pause");
	return 0;
}

多级指针:

#include <stdio.h>
#include <Windows.h>

int main1() {
	int gun = 888;//枪的内容
	int* locker2 = &gun;//第二个柜子里放有枪的地址
	int** locker1 = &locker2;//第一个柜子里放有第二个柜子的地址
	int*** locker0 = &locker1;

	printf("柜1存储指向的内容:0x%p,=柜2内容:0x%p,=枪的地址:0x%p\n", *locker1, locker2, &gun);
	printf("取第二个柜子里的枪:%d\n", *locker2);
	printf("一步到位取枪:%d\n", **locker1);
	printf("一步到位取枪:%d\n", ***locker0);//需要三把钥匙*

	system("pause");
	return 0;
}

//*p=sub_p
//指针能调取自己指向的内容
//p=&sub_p
//也能调取自己的内容,即指向内容的地址

指针内容与指针地址改变:

#include <stdio.h>
#include <Windows.h>

int main() {
	int sizes[] = { 50,22,13,24,25,16,37,48,29 };//胸围
	int len = sizeof(sizes) / sizeof(sizes[0]);
	int* p = sizes;

	//*指针运算级优先于+
	printf("larry likes:%d\n", *(p + 2));//指针位置加2
	printf("jessica likes:%d\n", *p + 10);//指针内容加10

	int* larry = sizes + 2;//=int *larry=&sizes[2]
	int* jessica = sizes + 5;//=int *jessica=&sizes[0]+5*sizeof(int)
	printf("jessica - larry=%d\n", jessica - larry);

	system("pause");
	return 0;
}

指针辅助逆转字符串:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
#include <Windows.h>
#define MAX 64
/*
让用户输入一个字符串,然后反向输出,注意:不能改变原来的字符串!
如: "12345"	->	"54321"
*/

int main() {
	char s[MAX];
	int len;
	printf("请输入想要逆转的字符串:");
	scanf_s("%s", s, MAX);
	len = strlen(s);

	//①指针反向扫描输出(不改变原字符串)
	//首地址char *p=s;
	char* p = &s[len - 1];//非首地址

	for (int i = 0; i < len; i++) {
		printf("%c", *p--);
		//p--;
	}
	printf("\n");


	//②直接反向输出(不改变原字符串)
	for (int i = len - 1; i >= 0; i--) {
		printf("%c", s[i]);
	}
	printf("\n");

	//③交换首尾值(改变原字符串)
	char tmp;
	for (int i = 0; i < len / 2; i++) {
		tmp = s[i];
		s[i] = s[len - i - 1];
		s[len - i - 1] = tmp;
	}
	for (int i = 0; i < len; i++) {
		printf("%c", s[i]);
	}
	printf("\n");

	system("pause");
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值