指针的深入理解

内存

⼀个⽐特位可以存储⼀个2进制的位1或者0

1byte = 8bit    1KB = 1024byte     1MB = 1024KB

1GB = 1024MB      1TB = 1024GB       1PB = 1024TB

解引用操作符(*)

char*    short*      int*       double*      为指针变量大小为4或8个字节

指针变量类型的意义

指针变量的⼤⼩和类型⽆关,只要是指针变量,在同⼀个平台下,⼤⼩都是⼀样的

指针的解引用
#include <stdio.h>
int main()
{
 int n = 0x11223344;
 int *pi = &n; 
 *pi = 0; 
 return 0;
}
#include <stdio.h>
int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 *pc = 0;
 return 0;
}

代码二:(char*)&n中的  (char*)的作用为强转char*

指针+-整数
#include <stdio.h>
int main()
{
 int n = 10;
 char *pc = (char*)&n;
 int *pi = &n;
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return 0;
}
00QSS878
00QSS878
00QSS879
00QSS878
00QSS882

char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化

void* 指针

void* 类型的指针可以接收不同类型的地址,但是⽆法直接进⾏指针运算

const修饰指针

const修饰变量
const int n = 0;
 printf("n = %d\n", n);
 int*p = &n;
 *p = 20;
 printf("n = %d\n", n);

被const修饰后n不可被修改但利用n的地址认可修改

const修饰指针变量

const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变

const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变

指针运算

指针+-整数

 *(p+i)相当于arr[i]

指针-指针

相同类型连续的指针相减得出  n个指针类型的大小

野指针

导致野指针出现的情况

1     

int *p;//局部变量指针未初始化,默认为随机值

2

指针指向的范围超出数组arr的范围时,p就是野指针

3

指针指向的空间释放

int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;
}

在函数调用完之后变量n所在的空间又还给了操作系统

规避野指针

1

指针初始化

NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错

int*p2 = NULL;

2

警惕越界访问

3

指针使⽤之前检查有效性

p = NULL;

if(p != NULL) //判断

{

//...

}

4

不要返回局部变量的地址

assert断⾔

头文件   <assert.h>  

 ⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”

——

assert(p != NULL);

验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序 继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。

——

真反1,假反0

定义宏:#define NDEBUG      可以将assert()

指针的使⽤和传址调⽤

实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参

传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量

数组名的理解

数组名为数组首元素的地址

#include <stdio.h>
int main()
{
 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 printf("&arr[0] = %p\n", &arr[0]);
 printf("arr = %p\n", arr);
 return 0;
}

&arr[0]=004FF9CC

arr      =004FF9CC

——————

***特例***   :

• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节

• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)

——————

指针,指针类,种类

二级指针

int a=20;

int *pa=&a;

int **paa=&pa;

**paa=30

结果:a=30

指针数组

指针数组的每个元素是地址,⼜可以指向⼀块区域

模拟二维数组int* parr[3] = {arr1, arr2, arr3};

printf("%d ", parr[i][j]);

数组指针

------------------------------

int (*p)[10]=&arr;

(*p)[1]=1;

二维数组指针传参

#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
 int i = 0;
 int j = 0;
 for(i=0; i<r; i++)
 {
 for(j=0; j<c; j++)
 {
 printf("%d ", *(*(p+i)+j));
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
 test(arr, 3, 5);
 return 0;
}

⼆维数组传参本质上也是传递了地址,传递的是第⼀ ⾏这个⼀维数组的地址

⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。

------------------------------

#include <stdio.h>
int main()
{
	int arr1[3] = { 4,5,6 };
	int arr2[3] = { 1,2,3};
	int arr3[5] = { 1,3,5,4,5};
	int* parr[3] = { arr1, arr2, arr3 };
	int*(*p)[3] = &parr;
	printf("%d",(*p)[1][1]);

	return 0;
}
字符指针

char ch='w';

char* ch=&ch;

函数指针

printf("test: %p\n", test);                     test: 005913CA

printf("&test: %p\n", &test);              &test: 005913CA

创建函数指针变量

void test()
{
 printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
 return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
函数指针数组

int (*parr1[3])();

typedef关键字

typedef 是⽤来类型重命名的

typedef unsigned int uint;   //将unsigned int 重命名为uint

typedef int* ptr_t;                //将int*重命名为ptr_t

但是对于数组指针和函数指针稍微有点区别:

typedef void(*pfun_t)[5];    //将int(*)[5]重命名为parr_t

typedef void(*pfun_t)(int);    //将 void(*)(int) 重命名为 pfun_t

简化代码: typedef void(*pfun_t)(int);

                 pfun_t signal(int, pfun_t);

转移表

int(*p[5])(int x, int y) = { 0, add, sub, mul, div };

ret = (*p[input])(x, y);

回调函数

void calc(int(*pf)(int, int))
{
 int ret = 0;
 int x, y;
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = pf(x, y);
 printf("ret = %d\n", ret);
}
case 1:
 calc(add);
 break;
 case 2:
 calc(sub);
 break;
 case 3:
 calc(mul);
 break;
 case 4:
 calc(div);
 break;
 case 0:
 printf("退出程序\n");
 break;
 default:
 printf("选择错误\n");
 break;

qsort

qsort函数排序整型数据

头文件<stdlib.h>

qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp); 

接收4个参数:一(数组名),二(数组长度),三(类型大小),四(比较函数)

比较函数:       

int int_cmp(const void * p1, const void * p2)
{
return (//自写);
}

  

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值