文章目录
一.空指针
#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=#×
//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;
}