目录
什么是指针
CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,⽽因为内存中字节很多,所以需要给内存进⾏编址 ,有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间。在计算机中我们把内存单元的编号成为地址,这个地址可以理解为指针。
指针知识点
取地址符(&),解引用(*),指针类型
我们可以通过取地址操作符(&)拿到的地址,然后通过*对地址进行解引用。
#include <stdio.h>
int main()
{
int a = 10;
int * pa = &a; //pa是一个变量存的是a的地址,int *的意思是*表明pa是指针变量
//int是指pa指向是一个整形类型
printf("%d",*pa);//*是对指针变量进行解引用
return 0;
}
通过上述的解释其实已经很好的初步理解指针是什么和怎么用。
补充:void * 无具体类型的指针(泛型指针),可以接受不同类型的地址,但无法直接进行指针运算,主要使用在函数参数部分,用来接受不同类型数据的地址。
const对指针变量的修饰
const修饰变量的时候叫常量,被修饰的变量本质还是变量,只是不能被修改。
const修饰指针变量,所修饰的内容不同因此作用也不一样
int const * p;//const 放在*的左边做修饰
左边:此时const限制的是*p那么此时所指向的内容是无法进行改变的,但是其指向是可以进行修改(指的是指向的地址)。
int * const p;//const 放在*的右边做修饰
右边:此时const限制的是指针的指向,但是可以通过指针变量修改其所指向的内容。
assert断⾔
assert.h 头⽂件定义了宏 assert() ,assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤。如果不符合,就报 错终⽌运⾏,并且给出报错信息提⽰,以及包含这个表达式的⽂件名和⾏号。
assert() 有⼏个好处:它不仅能⾃动标识⽂件和 出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问 题,不需要再做断⾔,就在 #include 语句的前⾯,定义⼀个宏 NDEBUG 。然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移 除这条 #define NDEBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语 句。
缺点:因为引⼊了额外的检查,增加了程序的运⾏时间。
指针运算
指针的基本运算有三种,分别是:
指针+- 整数 :此时打印的数字是3,因为数组是连续的所以只要找到首元素的地址,通过整数相加叫可以找到所指向的元素。
#include <stdio.h>
//指针+- 整数
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = arr;//首元素地址
int i = 2;
printf("p1=%d\n", *(p+i));//加整数
return 0;
}
指针-指针:前提是两个指针指向的是同一块空间,指针-指针的绝对值是指针与指针之间的元素个数,并不是字节数。
指针的关系运算:指针大小的比较。
什么是野指针,野指针的危害
野指针通常是因为指针变量未被正确初始化、指针释放后未被置空等原因产生的。
野指针的危害主要体现在以下几个方面:
(1)指向不可访问的地址:这种情况下,如果试图访问这个地址,可能会导致程序崩溃。
(2)指向一个可用的,但是没有明确意义的空间:这种情况下,程序可能可以正常运行,但是由于指针指向的是一个没有明确意义的空间,这可能会掩盖程序中的错误,使得错误难以发现和调试。
(3)指向一个正在被使用的空间:这是最危险的情况。如果对一个这样的指针进行解引用,并对其所指向的空间内容进行了修改,那么可能会破坏正在使用的数据,导致程序崩溃或数据损坏。
二级指针
二级指针变量是用来存放一级指针变量的地址,二级指针与二维数组没有对应的关系。
#include<stdio.h>
int main()
{
int a=10;
int *pa=&a;//pa是一级指针变量
int**ppa=&pa;//ppa是二级指针变量*ppa说明ppa是指针变量,int *是pa的类型
return 0;
}
字符指针变量
字符指针的形式:char *p
#include<stdio.h>
int main()
{
const char *p="abcdef";//const会对内容进行限制,修改系统会进行提示
printf("%c\n",*p);//打印是首个字母
printf("%s\n",p);//打印字符串时只提供首字符的地址即可
*p='q';//无法修改,字符串的内容是无法修改的
return 0;
}
《剑指offer》中收录了⼀道和字符串相关的笔试题
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char *str3 = "hello bit.";
const char *str4 = "hello bit.";
if(str1 ==str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 ==str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
这个例题的答案是:
str1 and str2 are not same
str3 and str4 are same,为什么会这样是因为str1和str2是两个数组因此指向的地址是不一样的,str3和str4指向的是⼀个同⼀个常量字符串。C/C++会把常量字符串存储到单独的⼀个内存区域, 当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。
指针与数组知识点
指针数组
存放指针的数组,数组的每个元素都是指针类型。例如int *p[5]就是一个含有5个指针变量的数组
#include <stdio.h>
//指针数组模拟二维数组
//指针数组
int main()
{
int arr[3]={1,2,3};
int arr2[3]={4,5,6};
int arr3[3]={7,8,9};
int * arr4[3]={arr,arr2,arr3};//对三个数组进行存放
int i=0,j=0;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",arr4[i][j]);
}
printf("\n");
}
return 0;
}
数组指针
数组指针是一个指针,它指向一个数组(一般是二维数组)。它的定义形式通常是 类型(*指针名)[大小]。这个指针可以用来访问整个数组,而不是单个元素。
#include <stdio.h>
//二维数组传参本质
void test(int(*p)[4],int a,int b)//数组指针的书写形式
{
int i=0,j=0;
for(i=0;i<a;i++)
{
for(j=0;j<b;j++)
{
printf("%3d",*(*(p+i)+j));//二维数组中*(p+i)==p[i]
}
printf("\n");
}
}
int main()
{
int arr[3][4] = {{1,2,3,4}, {5,6,7,8},{9,10,11,12}};
test(arr, 3, 4);
return 0;
}
总结
以上是最近这段时间的学习,主要涉及到指针的初识,指针与数组的联系,数组指针,指针数组之间的区别以及应用,指针是C语言的一个重要的内容因此一定要多加的练习与领悟。