关于c语言指针的详解(上)

前言

内存的使用和和管理

1.内存划分为一个个的内存单元,每个内存单元的大小是一个字节

bit 比特位

Byte 字节 1Byte=8bit

KB 1KB=1024Byte

MB 1MB=1024KB

GB 1GB=1024MB

内存单元的编号=地址=指针

一、指针基础

关键点:指针变量保存的是内存地址,利用解引用运算符(*)可以访问指针指向的特定内存位置中的数据。

指针变量,通常简称为指针(pointer),用来保存内存地址,即指针变量的值是内存地址。通常,一个变量包含一个数据值,如,一个整数、一个浮点数、一个字符。然而一个指针包含的则是另一个变量的内存地址,那个变量保存一个数据值。
1. 指针变量和地址

1.1取地址操作符(&)

在C语⾔中创建变量其实就是向内存申请空间,⽐如

⽐如,上述的代码就是创建了整型变量a,内存中 申请4个字节,⽤于存放整数20,其中每个字节都 有地址,上图中4个字节的地址分别是:

1 0x000000A10D36F884

2 0x000000A10D36F885

3 0x000000A10D36F886

4 0x000000A10D36F8847

1e=1*16+14

那我们如何能得到a的地址呢? 这⾥就得学习⼀个操作符(&)-取地址操作符

int* pa=&a(pa是变量用来存放a的地址pa叫指针变量)

当“与符号”(&)放在一个变量之前时,称为地址运算符(address operator),此时它是
一个单目运算符,返回变量的地址。所以,这里&a是a的地址。

1.2 指针变量

那我们通过取地址操作符(&)拿到的地址是⼀个数值,⽐如:0x006FFD70,这个数值有时候也是需要 存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中。

#include <stdio.h>
int main()
{
 int a = 10;
 int* pa = &a;//取出a的地址并存储到指针变量pa中
 //pa的类型是int*
 return 0;
 }

指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。

1.3如何拆解指针类型

我们看到pa的类型是 int* ,我们该如何理解指针的类型呢?

int a = 10;

int * pa = &a;

这⾥pa左边写的是 int* , * 是在说明pa是指针变量,⽽前⾯的 int 是在说明pa指向的是整型(int) 类型的对象。

1.4解引用操作符

我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?

在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。 C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。

int main()
 {
 int a = 100;
 int* pa = &a;
 *pa = 0;
 return 0;
 }

上⾯代码中第5⾏就使⽤了解引⽤操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa=0,这个操作符是把a改成了0.

1.5指针变量的⼤⼩

• 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节

• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节 X64环境输出结果

• 注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。

1.6指针变量类型的意义

char *, shor*, int*, float*等的大小都是4个字节,类型并不影响指针变量的大小

a的地址是0x003FF8F4

当pa的类型是int*时*pa改变的是a的四个字节,而当pa的类型为char*时,解引用只改变了a的一个字节

结论:指针的类型决定了对指针解引用时的权限有多大(一次能操作几个字节)

const修饰指针变量

const修饰的变量不能更改

一般来讲const修饰指针变量,const可以放在*的左边或者右边,意义不同

int main()
{
  int n=10;
  int m=100;

  int const *p =&n;
  //放在*的左边,限制的是指向的内容,不能通过指针变量修改它所指向的内容
  *p=20//error
  //int *const p=&n;
  //*p=20  ok
  //放在*的右边,限制的是指针变量本身(3),可以通过指针变量修改它所指向的内容
  
  p=&m;//如果const在*的右边则error
  return 0;
}

关于p有三个相关的值

1 p,p里面存放着一个地址

2 *p,p指向那个的对象

3 &p,表示的是取指针变量p的地址

指针运算

指针的运算有三种

1指针±整数

2指针—指针

3指针的关系运算

1 指针+-整数

int main()
{
  int arr[10]={1,2,3,4,5,6,7,8,9,10};
  int sz=sizeof(arr)/sizeof(arr[0]);
  int i=0;
  int* p=arr;//数组名其实就是数组首元素的地址
  for(i=0;i<sz;i++)
  {
   printf("%d ",*p)//printf("%d ",*(p+i));前者改变了p的地址,后者没改变p的地址
   p++;
  }


  return0;
}

2|指针—指针|得到的是指针和指针之间元素的个数。

前提条件是两个指针指向相同的空间

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d " ,& arr[9] - &arr[0]);

	return 0;
}//屏幕打印9

//模拟strlen函数
size_t my_strlen(char* p)
{
	char* end = p;

	while (*end != 0)
	{
		end++;

	}
	return end - p;

}

int main()
{
	char arr[10] = "abcdefghi";
	size_t len = 0;
	len = my_strlen(arr);
	printf("%d", len);

	return 0;
}屏幕打印9

指针的关系运算

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	while (p < &arr[sz])
	{
		printf("%d ", *p);
		p++;
	}

	return 0;
}

野指针

int main()
{
  //一个局部变量如果它不初始化的,它的值是随机的
  int *p;//p是局部变量没有初始化,它的值是随机的,如果将p中存放的值当地址解引用操作符就会形成非法访问
  *p=20;//p就是野指针
  int arr[10]={0};
  int i=0;
  int*p=arr;
  for(i=0;i<=10;i++);
  {
    *p=i;
    p++
  }
  //越界访问i=10时
  return 0;
}

如何规避野指针

不明确知道指针指向的空间时,可以给指针赋值NULL

指针的传值调用和传址调用

\\写一个函数交换两个整型变量的值

void Swap1(int x,int y)
{
  int z=0;
  z=x;
  x=y;
  y=z;
}

int main()
{
  int a=0;
  int b=0;
  scanf("%d %d",&a,&b);
  printf("交换前:a=%d b=%d\n",a,b);
  Swap1(a,b);
  printf("交换后:a=%d b=%d\n",a,b);

  return 0;
}//结果并没有交换

可以清楚发现

a 0x012ffa04

b 0x012ff9f8

x 0x012ff920

y 0x012ff924

a和x的地址不一样,b和y的地址不一样

传值调用,其实x,y是形参,出了函数就会销毁。x,y的值不影响a,b

void Swap2(int* x, int* y)
{
	int z = 0;
	z = *x;
	*x = *y;
	*y = z;
}

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前:a= % d b = % d\n", a, b);
	Swap2(&a, &b);
	printf("交换后:a= % d b = % d\n", a, b);

	return 0;
}传址调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值