一 :内存:把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取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;
}
本文详细解释了内存的基本结构,如字节和KB/MB/GB等单位转换,以及32/64位系统中的地址表示。重点介绍了指针的使用、类型、大小和权限,涵盖了野指针的产生和避免方法,还模拟实现了一个strlen函数和交换整数变量值的函数。

1230

被折叠的 条评论
为什么被折叠?



