指针与二级指针的理解与应用

指针

一.指针的概念

一切都是内存地址

C语言用变量来存储数据,用函数来定义一段可以重复使用的代码,它们最终都要放到内存中才能供 CPU 使用。

数据和代码都以二进制的形式存储在内存中,计算机无法从格式上区分某块内存到底存储的是数据还是代码。当程序被加载到内存后,

操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据。

CPU 只能通过地址来取得内存中的代码和数据,程序在执行过程中会告知 CPU 要执行的代码以及要读写的数据的地址。如果程序不小心出错,

或者开发者有意为之,在 CPU 要写入数据时给它一个代码区域的地址,就会发生内存访问错误。

这种内存访问错误会被硬件和操作系统拦截,强制程序崩溃,程序员没有挽救的机会。

CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,

它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。

总而言之,指针就是一种数据类型,里面装的是地址。

二.指针的定义:

  • 声明一个指针

数据类型 * 指针名

例如 int *p;

定义了一个名为p的指针,指向int数据.

在C语言中 ‘ * ’ 号,有三个含义:

1.数学里的加减乘除,乘。

2.指针在定义时,作为标记,标记该变量为指针变量。

3.指针在非定义时,加上指针变量名,则是解引用。也就是引用我们地址里保存的常量(数据)。 *p

&在C语言中的三个作用

1.取地址

2.与运算

3.逻辑与

//4.引用(C++)

地址打印格式为 : %p

p = 'a'; 这个是指向某个变量或常量的地址;

*p = ‘A’; 是把某个变量或常量的地址保存在指针p中

  • 解引用的使用

 

  • 指针与数组的关系
在某种程度上,我们的指针是可以跟数组互换的.例如:
    
#include <stdio.h>
#include <string.h>

int main()
{
    //定义指针
	int c = 4;
	int *p = &c;
	
	char stu[15]="hello world";
	char* s = stu;//定义一个char *指针s指向stu数组
	             /*1.指针指向数组实际上是指向数组的首地址
                  2.数组名用在表达式当中的含义是数组首地址
                  3.在表达式当中数组名使用取地址符号,代表数组的地址 */
	
	printf("stu[0] is %p\n",&stu[0]);//数组的首元素的地址
	printf("&stu   is %p\n",&stu);//整个数组的地址
 
	printf("%s\n",s);//s指向数组,访问数组从首地址开始的元素,
	printf("%s\n",stu);//stu在表达式当中代表数组首地址
 
	printf("%c\n",stu[0]);//stu数组中的首元素
	printf("%c\n",s[0]);//s指针的首地址的元素
	printf("%c\n",s[9]);
	
	int  b;//b存储的常量
	
	printf("int *p:%p\n",p);
	printf("int *p: %d\n",*p);
	printf("int  b: %p\n",&b); 
	
	return 0;
}
  • 指针的大小

通过sizeof我们去计算过 基本数据类型 int char double

指针用sizeof再次计算 int * char * double *

在32位机上面指针类型都是4字节

在64位机上所有的指针的都是8字节;

  • 指针的加减运算
int main(void)
{
	int buf[10] = {1,2,3,4,5,6,7,8};
	int *p = buf;
	
	printf("p存放的地址为: %p\n",p);
	
	p = p + 1;
	
	printf("p存放的地址为: %p\n",p);
	
	char buff[10] = "hello";
	char *q = &buff[4];
	printf("q存放的地址为: %p\n",q);
	
	q = q - 1;
	printf("q存放的地址为: %p\n",q);
	
	return 0;
}


   总结:   指针加法就是加一个数据类型的大小,指针减法就是减一个数据类型的大小;

 int main(void)
{
	int buf[10] = {10,20,30,40,50,60,70,80};
	int *p = buf;  //定义指针p指向数组buf
	
     //注意运算符优先级;
	printf("p 数据为:  %d\n",*(p+1));
	printf("p 数据为:   %d\n",*p+1);

	return 0;
}
  #注意点
      1.星号的优先级比加号的优先级高;
      2.*(p + 1) 由于括号的原因,先执行的p+1也就是数据类型+1;然后再对p+1进行解引用
      3.*p + 1,  由于*号的优先级比+号要高,所以先执行*p,再执行+1的运算.
          
  • 使用指针访问字符串
#include<stdio.h>

int main()
{
	char buf[15] = "hello wrold";
	char *p = buf;
	
	for( ;*p != '\0'; p++)
	{
		printf("%c \n",*p);
	}
	
	return 0;
}

    也可以写成(取决于后面你还需要不需要用到这个指针)
#include<stdio.h>

int main()
{
	char buf[15] = "hello wrold";
	
	
	for(char *p = buf; *p != '\0'; p++)
	{
		printf("%c \n",*p);
	}
	
	return 0;
}

    #注意:
        在使用for循环时,在判断语句里对指针一定要加上解引用.这样才能保证指针的地址能与值对上
        在使用字符串时,一定要注意数组的空间大小,是否有足够的空间储存‘\0’;
        如果没有空间储存‘\0’,则会导致越界访问,出现段错误;
  • 通过指针申请堆空间(动态内存)

通过之前的学习,我们知道了我们是不能直接往指针里面写数据的,如果想要写数据该怎么办呢?

//头文件
#include <stdlib.h>
//函数原型

//申请堆空间
void *malloc(size_t size);
//释放堆空间
void free(void *ptr);

//以上的3个函数malloc,calloc,realloc.
//都是用于申请堆空间的.只是申请的方式不一样.

//函数解析
    void *malloc(size_t size);
    
    返回值:
    void * 是一个通用型指针,假如你需要申请int类型的空间.那么它会返回 int *型的指针地址,
            也就是你所申请空间的首地址.
    //参数(size_t size) : 是申请空间的大小.
        //写法:
            (分配类型 *)malloc(分配元素个数 *sizeof(分配类型))

void free(void *ptr);
    参数void *ptr: 所需要释放的堆空间指针;
示例代码:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char * p = (char *)malloc(sizeof(char) * 10);
	stpcpy(p,"11111111");
	
	printf("%s\n",p);
	
	free(p);
	
	
	return 0;
}
  • 地址的偏移
假设有数组short buf[5] = {1,2,3,4,5};
数组ch的地址为 0x111 请计算出下面的值分别为多少?
buf+1 &buf+1 &buf[4] buf[4] buf+3 *(&ch[1]) &buf[1]+3
正确答案:
0x113  0x11b  0x119    5     0x117   2        0x119     
short类型 : 一个数据有占有2个字节的内存空间.
  • 指针与数组的结合
//假设有数组
char buf[12] = "helloworld";

char *p1 = NULL,
     *p2 = NULL;
     
      p1 = buf;
      p2 = &buf[4];
  //假设ch地址为0x113 ,
  那么p2 - p1 = ?
      p2 + p1 = ?   
      
      指针的相加减结论:
          (1)指针相减在数组当中才有意义,想减的结果为地址之间元素个数之差.
          (2)指针相加无意义,得不到想要得数据.只有在数组中++偏移的时候才会有意义.
          (3)在数组中每次偏移的++或--.都是偏移一个数据类型大小的地址.例如(sizeof(char)*偏移的数量)

二级指针

  • 概念

我们经常在书籍上看到空间的类型,那么空间的类型实际上就是变量的数据类型.

二级指针:与一级指针相同用于存储地址的指针.

注意:二级指针与数组无关,更与二维数组无关;

二级指针的操作遵循一点:

一个指针指向一个变量,*(解引用)这个指针,就是那个变量的本身.

 

  • 如何使用二级指针去访问一个数据

 

  • 二级指针的地址解析

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值