## 对指针的理解

本文详细介绍了C语言中的指针概念,包括声明、赋值和使用。通过实例解析了指针如何指向变量、数组、二维数组以及字符串。还探讨了指针在函数调用中的应用,以及作为函数参数的情况。强调了指针与数组、字符串及函数之间的交互,并给出了相关操作的正确和错误示例。
摘要由CSDN通过智能技术生成
  • 指针的定义声明,例: 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;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梦中千秋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值