C语言基础(第七期:指针)

目录

一、指针的本质

1.指针的定义

2.取地址操作符与取值操作符,指针本质

二、指针的传递使用场景

1.指针的传递

三、指针的偏移使用场景

1.指针的偏移

2.指针与一维数组

四、指针与malloc动态内存申请

1.指针与动态内存申请

2.栈空间与堆空间的差异


一、指针的本质

1.指针的定义

内存区域中的每字节都对应一个编号,这个编号就是“地址”,如果在程序中定义了一个变量,那么在对程序进行编译时,系统就会给这个变量分配内存单元,把变量地址存取变量值的方法称为“直接访问”,eg.printf("%d\n",i);scanf("%d\n",&i)等;另一种存取变量的方式称为“间接访问",即将变量i的地址存放到另一个变量中,在c语言中,指针变量是一种特殊的变量,他用来存放变量地址

定义格式:

基础类型 *指针变量名;

例如:int *i_pointer;

指针与指针变量是两个概念,一个变量的地址称为该变量的”指针”,例如:地址2000是变量i的地址,如果有一个变量专门用来存放另一变量的地址(即指针),那么称他为“指针变量”。

2.取地址操作符与取值操作符,指针本质

取地址操作符为&,也称引用,通过该操作符我们可以获取一个变量的地址值,取值操作符为*,也称解引用,通过该操作符我们可以得到一个地址对应的数据,

#include<stdio.h>
int main(){
    int i=5;
    int* p=&i;
    printf("i=%d\n",i);
    printf("*p=%d\n",&i);
    return 0;
}

但是要注意以下:

指针变量前面的“*”表示该变量为指针型变量

例如:float *pointer_1;

注意指针变量名是pointer_1,而不是*pointer_1;

指针的本质说白了就是地址。

二、指针的传递使用场景

1.指针的传递

我们来看下面代码

在本代码的主函数中,定义了整型变量,其初始化值为10,然后通过子函数修改整型变量i的值,但是,我们发现执行语句printf("after change i=%d\n",i);后,打印的值仍为10,子函数change并未改变变量的值

#include<stdio.h>
void change(int j){
    j=5;
}
int main(){
    int i = 10;
    printf("brfore change i = %d\n",i);
    change(i);
    printf("after change i = %d\n",j);
    return 0;
}

接下来 我们通过另一种代码来看他们的变化

#include<stdio.h>
void change(int* j){
    *j=5;
}
int main(){
    int i = 10;
    printf("brfore change i = %d\n",i);
    change(&i);
    printf("after change i = %d\n",i);
    return 0;
}

我们可以看到程序执行后,语句printf("after change i =%d\n",i);打印的值为5,难道是c语言的值传递的原理变了?并非如此,我们将变量i的值的地址传递给change函数时,实际效果j=&i,依然是值传递,只是这时我们的j是一个指针变量,内部存储的是变量i的地址,所以就通过*j就间接访问到了与变量i相同的区域,通过*j=5就实现了对变量i的值的改变,通过单步调试,我们依然可以看到变量j自身的地址是与变量i的地址依然不相等。

三、指针的偏移使用场景

1.指针的偏移

 上面我们介绍了指针的传递,指针即地址,就像我们找到了一栋楼,这栋楼的楼号是B,那么前面就是A,在后就是C,所以应用指针的另一个场景就是对其进行加减,但我们不用指针进行乘除,没有意义,就像把五个家庭乘以5一样,所以 我们把对指针的加减叫做对指针的偏移,指针的加法就是对指针向后偏移,指针的减法就是对指针向前偏移。

#include<stdio.h>
#define N 5
int main(){
    int a[N]={1,2,3,4,5};
    int *p;
    int i;
    p=a;
    for(i=0;i<N;i++){
        printf("%3d",*(p+i));//正序输出
    }
    p=&a[4];//指针指向最后一个元素
    for(i=0li<N;i++){
        printf("%3d",*(p-i));//逆序输出
    }
    printf("\n");
    return 0;
}

2.指针与一维数组

为什么一维数组在函数调用进行传递时,他的子长度函数无法知道呢,这时由于一维数组名中存储的是数组的首地址,如下例所示,数组名c中存储的是一个起始地址,所以子函数change中其实传入了一个地址,定义一个指针变量时,指针变量的类型和数组的数据类型保持一致,通过取值操作,就可将“h”改为“H”,这种方法称为指针法,获取数组元素时,也可以通过取下标的方式来获取数组元素并进行修改,这种方法称为下标法

#include<stdio.h>
void change(char* d){
    *d='H';
    d[1]='E';
    *(d+2)='L';
}
int main(){
    char c[10]="hello";
    change(c);
    puts(c);
    return 0;
}

四、指针与malloc动态内存申请

1.指针与动态内存申请

很多人在学习c语言的时候都会觉得数组长度固定很不方便,其实C语言的数组长度固定是因为其定义的整型,浮点型,字符型变量,数组变量都在栈空间里,而栈空间的大小在编译时是确定的,如果使用的空间大小不确定,那么就要使用堆空间。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int  main(){
    int i;
    char *p;
    scanf("%d",&i);
    p=(char)malloc(i);
    strcpy(p,"malloc success");
    puts(c);
    free(p);
    printf("free success\n");
    return 0;
}

要注意:malloc函数是用来申请空间的,在后续数据结构中会用到(此处记住即可)

2.堆空间与栈空间的差异

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//栈空间释放后,函数内部的所有的局部变量消失
char *print_stack(){
	char c[17]="I am print_stack";
	puts(c);
	return c;
} 
//堆空间不会因函数执行结束而释放
char *print_malloc(){
	char *p;
	p=(char *)malloc(20);
	strcpy(p,"I am print_malloc");
	puts(p);
	return p;
}
int main(){
	char *p;
	p=print_stack();
	printf("p=%s\n",p);
	p=print_malloc();
	puts(p);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

文艺小青年111

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

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

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

打赏作者

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

抵扣说明:

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

余额充值