文章目录
指针知识
归纳出来的都是运用的比较多的知识,什么二级指针之类的具体细节还是看书吧,用到太少了,用了也很容易错
基础知识
指针定义:用来存放内存地址的变量,指针变量是地址变量
指针运算符 * 单目运算符(从右往左) (取内容运算符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的值
指针的运算
一般指向后面存储单元的指针大于前面
指针移动:
- p=p+n 指针往后移n个同类型单元
- p=p-n
- p++
- 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];
区分方法:数组名带括号的就是数组指针,不带括号的就是指针数组。(这个类似于函数指针和指针函数的区别)
字符指针
注意:
-
要使用字符指针读取用户输入值 必须要分配内存
需要确保为该指针分配足够的内存来存储输入的字符串。
这可以通过动态内存分配函数(如 malloc、calloc 或 realloc)来实现,确保分配的内存大小足够容纳输入的字符串。 -
如果只是将字符指针指向一个已存在的字符串(例如,字符串常量),
就像下面的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;
}