指针 一详细知识

本文详细解释了内存的基本结构,如字节和KB/MB/GB等单位转换,以及32/64位系统中的地址表示。重点介绍了指针的使用、类型、大小和权限,涵盖了野指针的产生和避免方法,还模拟实现了一个strlen函数和交换整数变量值的函数。

一   :内存:把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节

内存单位转换:

1Byte = 8bit
1KB = 1024Byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB

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

二:   该如何理解编址

32位机器有32根地址总线,每根线只有两态,表⽰0,1【电脉冲有⽆】,那么⼀根线,就能表⽰2种含义,2根线就能表⽰4种含义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。

地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传⼊
CPU内寄存器。

三: 取地址操作符(&)

在C语⾔中创建变量其实就是向内存申请空间,&a取出的是a所占4个字节中地址较⼩的字节的地

指针变量和解引⽤操作符(*)

#include <stdio.h>
int main()
{
    int a=9;
    int* pa=&a;//创建指针变量
    * pa=5;//使用指针改变a的值
    printf("%d",a);
    return 0;
}

四:指针变量的⼤⼩

#include <stdio.h>
int main()
{
     printf("%d",sizeof(int*));
     printf("%d",sizeof(char*));
     printf("%d",sizeof(short*));
     printf("%d",sizeof(double*));
     return 0;
}

1.  32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
2.  64位平台下地址是64个bit位,指针变量⼤⼩是8个字节

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

五.指针变量类型的意义

1.

#include <stdio.h>
int main()
{
    int a=0x11223344;
    int* pa=&a;
    * pa=0;
    return 0;
}
//调试结果为a的四个字节全部归零
#include <stdio.h>
int main()
{
    char b=ox226617aa;
    char* pb=&b;
    *pb=o;
    return 0;
}//调试结果为只有一个字节被修改

结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。

2.

#include<stdio.h>
int main()
{
    int a=7;
    char b=9;
    int* pa=&a;
    char* pb=&b;
    prinf("%p %p",&a+1,pa+1);
    prinf("%p %p",&b+1,pb+1);
    return 0;
}

结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)

六:void* 指针:可以理解为⽆具体类型的指针(或者叫泛型指
针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进⾏指针的+-整数和解引⽤的运算

使⽤void*类型的指针接收地址:

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

⼀般 void* 类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以
实现泛型编程的效果。使得⼀个函数来处理多种类型的数据,在《深⼊理解指针(4)》中我们会讲解。

七:const 修饰指针

1.保证指针指向的内容不能通过指针来改变,但是指针变量本⾝的内容可变

int main()
{
    int a=8;
    int const *pa=&a;
    * pa=0;//不可进行此操作
    return 0;
}

2.保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

int main()
{
    int b=6;
    int* const pb=&b;
    int a=5;
    int* pb=&a;//不可进行此操作
    return 0;
}

3.既不改变指针,也不改变指针内容

int main()
{
    int a=9;
    int b=8;
    int const * const pa=&a;
    *pa=0;//不可进行此操作
    int*pa=&b;//不可进行此操作
    return 0;
}

八:指针运算:

1.• 指针+- 整数:

上面已提过:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* pa = &arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(pa + i));
	}
	return 0;
}

2.指针-指针

#include <stdio.h>
int main()
{
	char arr[] = "abcdef";
	char* pa =&arr;
	char* pb = &arr;
	while (*pb)
	{
		pb++;
	}
	printf("%d", pb - pa);
	return 0;
}

3.指针的关系运算

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* pa =& arr;
	int* pb = &arr[3];
	if (pa < pb)
	{
		printf("hehe");
	}
	return 0;
}

九.野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

1. 指针未初始化

#include <stdio.h>
int main()
{
	int a = 9;
	int* pa;
	return 0;
}

2.指针越界访问

int main()
{
	int arr[4] = { 1,2,3,4};
	int* pa = &arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(pa+ i));
	}
	return 0;
}

3. 指针指向的空间释放

#include <stdio.h>
test()
{
	int b = 200;
	int* pb = &b;
}
int main()
{
	int a = 9;
	int* pa = &a;
	test();
	printf("%d %d",*(pa),*(pb))
	return 0;
}

十:如何规避野指针

1.指针初始化:

#include <stdio.h>
int main()
{
	int* pa = NULL;
	return 0;
}

2.⼩⼼指针越界

3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性

十一.assert 断⾔(assert(p != NULL);)

头文件  #include <assert.h>

#define NDEBUG
#include <stdio.h>
#include <assert.h>
int main()
{
	int a = 9;
	int* pa = &a;
	assert(pa != NULL);
	printf("hehe");
	return 0;
}

十二:strlen的模拟实现

#include <stdio.h>
#include <assert.h>
size_t my_arr(char* p)
{
	assert(p != NULL);
	size_t  count = 0;
	while (*p)
	{
		count++;
		p++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdefd";
	size_t len=my_arr(&arr);
	printf("%zd", len);
	return 0;
}

十三:写⼀个函数,交换两个整型变量的值

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void swap(int* pa, int* pb)
{
	int z = 0;
	z = *pa;
	*pa = *pb;
	*pb = z;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前:a=%d b=%d\n", a, b);
	swap(&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、付费专栏及课程。

余额充值