## 对指针的理解

Posted on   梦中千秋  阅读(30)  评论(0编辑  收藏  举报
  • 指针的定义声明,例: int *p;,就声明了一个基类型为int的指针p,指针名为p。但是只声明了,还未给其指向。
  • 声明时同时给定指向: int i; int *p = &i; ,声明的同时,让其指向int型变量i的地址。
  • 又或者声明后,再给出指向: int i; int *p; p=&i; ,同样让其指向变量i的地址。
//声明变量 i ,赋值为 1
int i = 1;
//声明指针变量 p ,此处的 * 不表示取值 , 而是为了区别 表示声明的是一个指针变量,不是int型变量
int *p;
//使指针p指向变量i的地址 , &符号,表示取其地址
p = &i;
//通过指针变量p 打印变量i的值,此处 * 表示取其指向地址的值
printf("%d", *p); //打印结果 1
//如没有 * 符号 , 表示p指向的地址
printf("%d", p); //打印结果为指针p所指向的地址: 为不确定的值

注意区别int型变量与int 型指针变量的声明与赋值:

  • 对于int 型的声明: int i; 声明时同时赋值: int i = 1; 声明后再赋值: int i; i = 1;

  • int i = 1; 表示 将常量1赋值给int型变量 i

  • int *p = &i; 应理解为 使指针p 指向 变量i 的地址,而不是将变量i的地址赋值给指针p

指针更常用的场景之一是与数组配合使用

//声明一个数组a ,a表示的是数组的首地址,也就是数组中第一个元素的地址
int a[3] = {1,3,5};
//声明一个指针变量p , 并使其指向数组 a
int *p = a;
//打印数组中第一个元素
printf("%d", *p); //1
//打印数组中第二个元素,注意括号不可省
printf("%d", *(p+1)); //3
//省略则 表示打印数组中第一个元素 加上1
printf("%d", *p+1); //2
//使指针p指向下一个地址,即数组中第二个元素的地址
p=p+1;
//此刻p指向的是数组中的第二个元素的地址
printf("%d", *p); //2
  • 若有定义int a[3]; int *p = a;数组中元素的引用方式有:a[i] , *(p+i) , p[i] , *(a+i) 四种 ,常用的常常为前面两个 。 但应明白四者等价。

二维数组:

//二维数组的声明
int a[2][3] = {{1,2,3},{4,5,6}};
  • a 同样表示的是数组首地址,但是数组中第一个元素是一个包含3个元素的一维数组。实际是一个指向一维数组的地址的指针。

  • 这时,*a并不能取到第一个元素的值了,*a 表示数组中第一个元素的地址,也就是一维数组的地址。再进行一次取值,**a 则表示取 数组中第一个元素(指 {1,2,3})中的第一个元素(指1)的值,可能已经有点绕了。

  • 若有定义int *p; ,试图将指针p指向a: p=a; , 实际是不对的 , 应将p定义为指向 由3个元素组成的一维数组的 指针: int (*p)[3]; .注意此处括号不可省,不能定义为 int *p[3]; (这样表示定义一个有三个指针变量元素的指针 数组) , 也不可定义为int **p;

  • 注意区别 *int (p)[3]; 与 *int p[3]; 的含义

  • 虽然定义int *p; 的指针p不可直接指向a,但是可以指向a中 第一个元素 的地址p = a[0];

区别其不同的指向方式:

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
//指针 数组 , 它还是数组,只不过其中的元素是int为基类型的指针
int *p[2];
for (int i = 0; i < 2; i++) p[i] = a[i];
//表示 取第二个元素的首元素的值
printf("%d\n",*p[1]);
//与a[1][2]含义相同
printf("%d\n",p[1][2]);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
printf("%d\t", *(*(p + i) + j));
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
//指向 由3个元素组成的一维数组的 指针,但是它还是 指针
int(*p)[3];
p = a;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
printf("%d\t", *(*(p + i) + j));
//当i和j都为0时
printf("%d\t", **p);

指针与字符串及字符串数组

注意不同的定义方式 , 及其定义方式的区别

//正确的
char s[] = "hello";
char s1[10] = "hello";
//s2表示:字符串的首字符的地址
char *s2 = "hello";
char *s3;
s3 = "hello";
//输出方式
printf("%c",*s2); //以字符型格式输出: h
printf("%s", s2); //以字符串格式输出: hello
puts(s2); //使用字符串函数输出函数输出: hello
//错误的 , 只能采用循环一个一个字符的赋值
char s1[10];
s1 = "hello";
s1[10] = "hello";
char *s2;
*s2 = "hello";
//正确的
char s1[10];
gets(s1);
//错误的
char *s2;
gets(s2);
  • 数组形式不能进行自加操作,即不能改变,而指针型定义的字符串可以改变
char s1[] = "hello";
s1 = s1 + 1; //不合法,数组首地址不可变
char *s2 = "hello";
s2 = s2 + 1; //合法
printf("%c",*s2); //输出: e
puts(s2); //输出: ello
//试图将首字母 h 改为大写 H
//不合法,字符串常量不能改变
char *s1 = "hello";
*s1 = 'H';
// 合法
char s2[10] = "hello";
s2[0] = 'H';

字符串数组 (二维数组) 的定义与遍历引用:

char *s1[] = {"Java", "Python", "C", "JavaScript"};
char s2[][10] = {"Java", "Python", "C", "JavaScript"};
for (int i = 0; i < 4; i++){
puts(s1[i]);
puts(s2[i]);
}

指针与函数

  • int (*p)(); 声明 基类型为无参且返回类型为int型函数的指针,其基类型为: int (*)()
  • int *p(); 声明 返回类型为int *的函数
#include <stdio.h>
void fun1(){
printf("fun1");
}
int fun2(int x){
printf("fun%d", x);
}
int fun3(int x, int y){
printf("fun%d", x + y);
}
int main(){
//无参无返回值
void (*p1)() = fun1;
(*p1)();
//带参与返回值
int (*p2)(int) = fun2;
(*p2)(2);
//多个参数
int (*p3)(int, int) = fun3;
(*p3)(2, 1);
return 0;
}

函数指针作函数参数

#include <stdio.h>
int max(int x,int y){
return (x>y?x:y);
}
int min(int x,int y){
return (x<y?x:y);
}
//以函数指针作函数形参, x、y表示形参函数指针m 的参数。x、y不必须,可省。
int fun(int x,int y,int (*m)(int,int)){
return (*m)(x,y);
}
int main()
{
//求两者 最大值
printf("%d",fun(3,9,max));
//求两者 最小值
printf("%d",fun(3,9,min));
return 0;
}
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示