指针知识+题目总结

指针知识

归纳出来的都是运用的比较多的知识,什么二级指针之类的具体细节还是看书吧,用到太少了,用了也很容易错

基础知识

指针定义:用来存放内存地址的变量,指针变量是地址变量

指针运算符 * 单目运算符(从右往左) (取内容运算符or间址访问运算符)

int *sum=&变量
    或者
int *sum;
sum = &变量;

1.int *p=&n 实际上int为n的类型

2.int *p等同于int* p

3.int* p,q 指的是指针变量p和普通int类型变量q`

*指针变量=一个指针变量代表的值

4.(*p)++指的是变量p指向的变量值自增 p的值没变
5.*p++等价于*(p++) p的值变了

6.两个指针变量类型不同,赋值时必须==强制类型转换== p2=(float*)p1;

printf("p4=%d\n",*(int*)p4)  //注意(int*)p4是强制类型转换后的地址,*(int*)p4则是值

7.空类型指针:void类型
空指针:指针变量被初始化为NULL ‘\0’

p指向a

int a=5;  //假设变量a地址为1001
int *p=&a;  //p的值为1001,称之为p指向a

直接访问方式:直接用x或&x访问变量的方式,如x=5
间接访问方式:通过指针变量p访问a,取出a的地址,按照地址读取a的值


指针的运算

一般指向后面存储单元的指针大于前面

指针移动:

  1. p=p+n 指针往后移n个同类型单元
  2. p=p-n
  3. p++
  4. p- -
    如果为float变量,p=p+2,指的是往后移动2*sizeof(float)=8个字节

两个指针相减: 相差存储单元个数or两个指针所指数组元素之间相差的元素个数。

加法没意义


指针变量作为函数参数(地址传递方式)

与值传递区分开
这个会改变实参值

void function(int n,int *sum){  //注意有*
    ...
}
function(m, &sum1);  //注意传的是地址,需要&

指针和一维数组

数组指针是一个指针,它指向数组的首元素。通过数组指针,你可以访问数组的元素,并可以通过指针的增减操作在数组中移动。

数组名代表数组所在连续存储空间的首地址
注意p++可以a++不行

1.表示a[5]的地址
p+5 a+5 &a[5]

2.表示a[5]的值
*(p+5) *(a+5) a[5] p[5]

注意 : 所有指针必须初始化

int a[] = {1, 2, 3};
int *s; 
s = a; // 初始化
s[0] = a[0]; // 将a数组的第一个元素的值赋给s指向的位置
//因为s初始化了所以这段代码正确

以下为反例:

int c, *s, a[]={1, 3, 5};
s[0]=a[0]  //没初始化不能直接这样赋值

在这里插入图片描述


指针和二维数组

下面这个图片注意一下4和5

在这里插入图片描述

就是 &a[0][0]+i*4+j a[0]+i*4+j

因为二维数组连续存储相当于横着存放

a[0][0]  a[0][1]  a[0][2]
a[1][0]  a[1][1]  a[1][2]
a[2][0]  a[2][1]  a[2][2]
//存放为  a[0][0]  a[0][1]  a[0][2]  a[1][0]  a[1][1]  a[1][2]  a[2][0]  a[2][1]  a[2][2]

假设a[0][0]地址为1,依次过来a[2][1]的地址则为7

因此如果是以第一个元素为起点,要想访问到a[2] [1]的地址,则需要 &a[0][0]+i*3+j

在这里插入图片描述


数组指针和指针数组

数组指针

数组指针:本质是一个指针,指向了一个数组,数组中的每个元素都是某种数据类型的值(比如 int 类型)。

int (*p)[n]; //定义了一个数组指针,指向一个大小为n的数组,数组中的每个元素都是int类型
数组指针也称行指针,也就是说,当指针p执行p+1时,指针会指向数组的下一行,如:

int a[3][4];
int (*p)[4];	//p是一个数组指针,指向了一个包含4个int型元素的数组
p=a;			//将二维数组的首地址赋给p,即a[0]或a[0][0]
p++;			//跨过第一行,p指向了a[1][0]

以数组指针作为函数参数,在函数中p[i] [j]就可以等同于主函数中的a[i] [j]使用(就不用 *(p+i)这种表示方式来表示某个元素)


指针数组

指针数组:本质是一个数组,该数组中的每个元素都是一个指针。

int*p[n]; //定义了一个指针数组,数组大小为n,数组中的每个元素都是一个int*指针
指针数组是一个包含若干个指针的数组,p是数组名,当执行p+1时,则p会指向数组中的下一个元素。

int a[3][4];
int *p[3];		//定义了一个数组,该数组中有3个int*指针变量,分别为p[0]、p[1]、p[2]
//p++;			//若执行此语句,则数组p指向下一个数组元素
for(int i=0;i<3;i++){
    p[i]=a[i];	//数组p中有3个指针,分别指向二维数组a的每一行
}

访问数组
补充一下二维数组的访问方式:对于一个二维数组 p [ m ] [ n ] p[m][n] p[m][n],表示其第 i 行第 j 列的元素的方式有以下4种:

p [i] [j]		//方式1
*(p[i]+j)		//方式2
*(*(p+i)+j)		//方式3
(*(p+i))[j]		//方式4

总结
总结一下数组指针和指针数组的区别:

定义不同
数组指针:本质是一个指针,指向了一个数组

指针数组:本质是一个数组,该数组中的每个元素都是一个指针

写法不同
数组指针:int (*p)[n];

指针数组:int *p[n];

区分方法:数组名带括号的就是数组指针,不带括号的就是指针数组。(这个类似于函数指针和指针函数的区别)


字符指针

注意:

  1. 要使用字符指针读取用户输入值 必须要分配内存
    需要确保为该指针分配足够的内存来存储输入的字符串。
    这可以通过动态内存分配函数(如 malloc、calloc 或 realloc)来实现,确保分配的内存大小足够容纳输入的字符串。

  2. 如果只是将字符指针指向一个已存在的字符串(例如,字符串常量),
    就像下面的char *str = “I am a student.”;
    那么无需显式分配内存,因为字符串常量在程序的数据段中已经存在。

字符指针和字符数组的区别

1.赋值方式比较:

(字符数组)

char str[16];
str="I am a student."; //这是错误的
//只能直接char str[17] = "I am a student.";
//或者用strcpy,两个字符数组之间不能直接给值

(字符指针)

char *str;
str="I am a student."; //这是可以的

2.运算比较:

字符指针可以++或 - -,字符数组名不行

void main(){
    char *string="I am a student.";
    string=string+7;
    printf("%s\n",string);
}
//运行结果:student.

在这里插入图片描述


返回指针的函数

返回指针型数据,即返回一个地址

形如int *fun(int x,int y)

int *fun(int x,int y){
    ...
	return 地址或指针变量
}

题目

指针输入/输出一维数组元素

本题目用指针变量输入、输出数组arrA的元素值

最主要的是循环以指针变量p为基底,p的范围是地址!!!

#include <stdio.h>

int main(){
	int *p,a[5];
	for(p=a;p<a+5;p++)	scanf("%d",p);
	for(p=a;p<a+5;p++)  printf("%d ",*p);
	return 0;
}
//注意:循环中p是地址,所以加到的范围就是a[5]的地址,及a+5,不是5

字符串比较函数

本题目要求写一个函数 mystrcmp实现字符串比较,相等输出 0,不等输出其差值,在主函数输出比较结果。

#include <stdio.h>
#define N 20

int mystrcmp(char *s1,char *s2){
	while(*s1!='\0'&&*s2!='\0'){
		if(*s1==*s2){
			s1++;
			s2++;  //  
		}else return *s1-*s2;  //返回从第一个不同的地方开始的差值
	}
	while(*s1!='\0') return *s1;  //s1和s2部分相同但s2提前结束
	while(*s2!='\0') return -*s2;  //s1和s2部分相同但s1提前结束
	return 0;  //s1和s2完全相同
} 

int main(){
	char str1[N],str2[N];
	gets(str1);
	gets(str2);
	
	printf("compare result=%d\n",mystrcmp(str1,str2));
	return 0;
	
	return 0;
}

使用函数实现字符串部分复制

本题要求编写函数,将输入字符串t中从第m个字符开始的全部字符复制到字符串s中。

函数接口定义:

void strmcpy( char *t, int m, char *s );

函数strmcpy将输入字符串char *t中从第m个字符开始的全部字符复制到字符串char *s中。若m超过输入字符串的长度,则结果字符串应为空串。

(中文不行)

#include <stdio.h>
#define N 20

void mystrcpy(char *s1,int m,char *s2){
	int i;
	for(i=0;s1[i+m-1]!='\0';i++) s2[i]=s1[i+m-1];
	s2[i]='\0'; //注意不要忘了结束符
}

int main(){
	int m;
	scanf("%d",&m);
	getchar();
	char str1[N],str2[N];
	gets(str1);
	mystrcpy(str1,m,str2);
	puts(str2); 
	return 0;
}

查找子串

本题要求实现一个字符串查找的简单函数。

函数接口定义:

char *search( char *s, char *t );

函数search在字符串s中查找子串t,返回子串t在s中的首地址。若未找到,则返回NULL。

#include <stdio.h>
#define N 30
//因为是返回地址,所以用指针函数
char *search(char *s,char *t){ 
	char *p1,*p2,*p3;
	for(p1=s;*p1!='\0';p1++){
		p2=p1;
		p3=t;
		
		while(*p3!='\0'&&*p2==*p3){
			p2++;
			p3++;
		} 
		
		if(*p3=='\0') return p1; //判断p3是否完全符合
	}
	return NULL;
}

int main(){
	char s[N],t[N],*pos;
	gets(s);
	gets(t);
	pos=search(s,t);
	if(pos!=NULL)
		printf("%d\n",pos-s);
	else 
		printf("-1\n");
	return 0;
}

7-1 矩阵转置

PTA | 程序设计类实验辅助教学平台 (pintia.cn)

用指针实现将一个3*3的整型矩阵转置。

要求定义并调用函数void move(int *pointer),实现上述矩阵转置的功能。

输出格式:每行数据之间以空格分隔,最后一个数据后面没有空格

输入样例:

1 2 3
4 5 6
7 8 9

输出样例:

1 4 7
2 5 8
3 6 9

按照题目要求若以a[0] [0]地址为参数传递:

运用知识:指针和二维数组

#include <stdio.h>
int i,j;

void move(int *pointer){
	int temp;
	for(i=0;i<3;i++){
		for(j=i+1;j<3;j++){
			temp=*(pointer+i*3+j);
			*(pointer+i*3+j)=*(pointer+j*3+i);
			*(pointer+j*3+i)=temp;
		}
	}
}

int main(){
	int a[3][3];
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			scanf("%d",&a[i][j]);
		}
	}
	move(&a[0][0]);//move(a[0]);
	
	 for (i = 0; i < 3; i++) {
        printf("%d %d %d\n", a[i][0], a[i][1], a[i][2]);
    }

	return 0;
}

行指针写法

运用知识:数组指针

#include <stdio.h>
int i,j;

void move(int (*p)[3]){
	int temp;
	for(i=0;i<3;i++){
		for(j=i+1;j<3;j++){
			temp=p[i][j];
			p[i][j]=p[j][i];
			p[j][i]=temp;
		}
	}
}

int main(){
	int a[3][3];
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			scanf("%d",&a[i][j]);
		}
	}
	move(a); //注意行指针是传一整个数组过去
	
	for (i = 0; i < 3; i++) {
        printf("%d %d %d\n", a[i][0], a[i][1], a[i][2]);
    }

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JaneHan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值