C语言指针的图文详解

目录
  • 指针是什么?
  • 指针和指针变量
    • 1. 指针类型决定了指针进行解引用操作的时候,能访问空间的大小
    • 2. 指针加减整数
  • 野指针
    • 野指针的成因
  • 指针和数组
    • 二级指针
    • 指针数组、数组指针
  • 总结

指针是什么?

指针(Pointer)是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。

换句话说就是可以通过指针找到以它为地址的内存单元。

理解:内存图解。

指针是个变量,存放内存单元的地址(编号)。

int main(){
    int a = 10;//在内存中开辟空间存储
    int* p = &a;//先对变量a取出它的地址,可以使用&操作。
    			//将a的地址存放在p变量中国,p就是一个指针变量
}

小结:指针就是变量,内容是地址。(存放在指针中的值被当做地址处理)

指针的大小

  • 在32为计算机上指针大小4字节。
  • 在64为计算机上指针大小8字节。

指针和指针变量

关于地址

printf("%p \n",&a);//%p地址格式   &a取a的地址
int* p = &a;
//int*指针类型
//p 指针变量
//&a 取地址

使用

*p //解引用操作符
int a =10;  //在内存中存储10   还有char*等类型
int* p = &a;//定义指针,位置为a的内存
*p = 20;    //更改指针指向内存的 值
printf("a= %d",a);//结果为a=20

int* p的理解 p是int类型的一个指针(仅此而已),一般*p指向的也是一个int型的

1. 指针类型决定了指针进行解引用操作的时候,能访问空间的大小

int main(){
    int n = 0x112233;
    char* p = (char*)&n;
    int* pi = &n;
    *pc = 0;  //在调试的过程中观察内存的变化。
    *pi = 0;
    return 0;
}
int*;  *p可以访问4个字节。
char*; *p可以访问1个字节。
double*;  *p可以访问8个字节。

原因 是类型本身所需的内存空间就是指针可以控制的空间。

意义:使用时选用合适的指针类型进行定义

2. 指针加减整数

int main(){
    int a = 0x11223344;
    int* p1 = &a;
    char* p2 = &a;
    printf("%p\n",p1);
    printf("%p\n",p1+1);
    printf("%p\n",p2);
    printf("%p\n",p2+1);
    return 0;
}

int类型时0C->10 变化4, char类型时0C->0D 变化1。

理解:指针加一不是指向下一个紧挨着的地址,是指向下一个指针变量对应的类型变量开始的地址。

意义 指针类型决定了:指针走一步走多远(指针的步长)

野指针

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

野指针的成因

1.指针未初始化

int main(){    int a;//局部变量不初始化,默认是随机值    int *p;//局部的指针变如果没有初始化,就被初始化为随机值。}int main(){
    int a;//局部变量不初始化,默认是随机值
    int *p;//局部的指针变如果没有初始化,就被初始化为随机值。
}

2.指针越界访问

int main(){
    int arr[10];
    int *p = arr;
    for(int i = 0;i<12;i++){
        p++;
    }
    //当指针的范围超出数组的范围时,p就是野指针。
}

3.指针指向的空间释放

int main(){
    int arr[10];
    int *p = arr;
    for(int i = 0;i<12;i++){
        p++;
    }
    //当指针的范围超出数组的范围时,p就是野指针。
}

解析:在main函数调用test()时,进入test()函数,int a语句开辟临时的内存空间并将这个内存空间存储为10;返回函数的时候返回的临时的a的地址给*p,然后test函数已经在执行完test函数后结束,a的内存空间被销毁。这时的*p就是指向的地址正确但是内容已经改变。

将未知位置的值进行修改是非常危险的

如何避免野指针

1.指针初始化

2.小心指针越界

3.指针指向内存释放 即 指向NULL

4.指针只用之前检查有效性

指针运算

1.指针加减整数

2.指针-指针

3.指针的关系运算

指针加减指针

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

指针-指针

int main(){
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    printf("%d",&arr[9]-&arr[0]);//输出9   中间元素的个数。
    printf("%d",&arr[0]-&arr[9]);//输出-9
    return 0;
}

指针减指针必须是自己减去自己。否则结果不可预知。

指针实现strlen()

int my_strlen(char* str){
    char* start = str;
    char* end = str;
    while(*end != '\0'){
        end++;
    }
    return ;
}
int main(){
    char arr[] = "hello";
    int len = my_strlen(arr);
    printf("%d\n",len);
    return 0;
}

指针的关系运算

int main(){
    float values[5];
    for(float* vp=&values[5];vp>&values[0];){
        printf("haha ");
        *--vp = 0;
    }
    return 0;
}

这里碰到了两个问题 1. values[5]本身不属于数组的部分。但是可以使用。经测试values[5]不会警告,但是values[-1]及以下或values[6]及以上都会报错。2.指针的加减是类型位置的移动数组总也就是一个一个往过走。

for(float* vp=&values[5-1];vp>=&values[0];vp--){
    printf("haha ");
    *vp = 0;
}

这里在绝大多数的编译器上是可以顺利完成任务的,然而我们应该避免这第二种写法,因为标准不能保证他是可行的。

标准规定:允许指向数组元素的指针和指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个位置的指针进行比较。

指针和数组

int main(){
    int arr[10]={0};
    printf("%p\n",arr);  //地址-首元素地址
    printf("%p\n",&arr[0]);
}

一般情况数组名都代表首元素的地址

除了:

1. &数组名 这时数组名代表整个数组的地址

2. sizeof(数组名) 这时也是代表整个数组。

二级指针

将第一层指针1想成变量,再取这个变量的地址存为一个指针2。那么指针2指向指针1,指针1指向原变量。原变量的地址存在了指针1中,指针1的地址存在了指针2中。

int main(){
    int a = 10;
    int* pa = &a;
    int** ppa = &pa;//ppa就是二级指针。
    //存在三级及以上指针,(无限套娃)
}

指针数组、数组指针

指针数组其实是个数组,数组指针是个指针

指针数组:存放指针的数组

int a = 10;
int b = 20;
int c = 30;
int* arr[3] = {&a,&b,&c};//指针数组

数组指针:指向数组的指针。

main(){
int a = 10;
int* pa = &a;
int** ppa = &pa;//ppa就是二级指针。
//存在三级及以上指针,(无限套娃)
}

### 指针数组、数组指针

指针数组其实是个数组,数组指针是个指针

<u>**指针数组**</u>:存放指针的数组

~~~c
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = {&a,&b,&c};//指针数组

数组指针:指向数组的指针。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言结构体指针引用详解

    目录 指向结构体变量的指针 指向结构体数组的指针 结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针. 指向结构体变量的指针 前面我们通过"结构体变量名.成员名"的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针. 前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址.如果定义一个指针变量 p 指向这个地址的话,p 就可以指向结构体变量 student1 中的任意一个成员. 那么,这个指针变量定义成

  • C语言指针用法总结

    1.先谈谈内存与地址 引例: 计算机的内存看成大街上的一排房屋,每个房屋都要有门牌号,这个就相当于计算机的内存地址,而房屋里面住的人.家具等等就相当于需要存放的各种各样的数据,所以要想访问这些数据就得知道它的内存地址. **bit:计算机的内存便是由数以亿万计的位(bit)**组成,每个位的容纳值为0或1. byte:字节,一个字节包含8个位(bit),可以储存无符号unsigned类型的值为0-255(28-1),储存有符号signed类型的值为-128到127.无符号类型就是非负数,而有符号

  • c语言的指针数组详解

    指针如何指向数组,并读取数组中的元素: #include <stdio.h> int main() { int arr[3] = {1,2,3}; int *p; p = &arr[0];//此句也可以写成 p = arr: for(int i=0;i<3;i++) { printf("第%d个元素值为:%d\n",i,*(p+i)); /*应注意这里指针的定义类型:p+i并不是指p的地址+1, 而是偏移一个类型的字节数,这里的类型是int,所以偏移4个字节*

  • C语言之初识指针

    指针是什么? 那到底什么是指针呢,其实指针和之前学习的变量基本相似,不过变量里面放的是一些值,而指针里面放的是它所指的地方的地址.在声明一个变量是,计算机就会为该变量预留一个位置,而指针所指☞的就是那个位置. 举个例子: int a = 10;//设置一个变量a的值为10 int *p = &a;//p这个指针里面就放的是a的地址 而&这个符号,就是取地址符,就像我们在使用scanf函数时  scanf("%d",&a); 这个a前面的&是一个意思,就是

  • C语言基础双指针移除元素解法

    本题方法:双指针.知识比较基础,思路简单 题目: 我的题解: int removeElement(int* nums, int numsSize, int val) { int i=0,j=0; int cnt=0; //计数器,用来统计val的个数 while(j<numsSize) { if(nums[j]!=val) //1 { nums[i]=nums[j]; i++; j++; } else //2 { j++; cnt++; } } return numsSize-cnt; //3

  • C语言指针的图文详解

    目录 指针是什么? 指针和指针变量 1. 指针类型决定了指针进行解引用操作的时候,能访问空间的大小 2. 指针加减整数 野指针 野指针的成因 指针和数组 二级指针 指针数组.数组指针 总结 指针是什么? 指针(Pointer)是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址. 换句话说就是可以通过指针找到以它为地址的内存单元. 理解:内存图解. 指针是个变量,存放内存单元的地址(编号). int main(){ int a = 10;//在内存中开辟空间存储 int* p = &a;

  • C语言指针数组案例详解

    指针与数组是 C 语言中很重要的两个概念,它们之间有着密切的关系,利用这种 关系,可以增强处理数组的灵活性,加快运行速度,本文着重讨论指针与数组之 间的联系及在编程中的应用. 1.指针与数组的关系 当一个指针变量被初始化成数组名时,就说该指针变量指向了数组.如: char str[20], *ptr; ptr=str; ptr 被置为数组 str 的第一个元素的地址,因为数组名就是该数组的首地址, 也是数组第一个元素的地址.此时可以认为指针 ptr 就是数组 str(反之不成立), 这样原来对数

  • C语言 指针数组进阶详解

    目录 指针与数组中的sizeof与strlen sizeof strlen 数组名 1.一维数组 整型数组 字符数组 指针数组 2.二维数组 指针笔试题 笔试题1 笔试题2 笔试题3 笔试题4 笔试题5 前言:指针与数组的知识往往让我们无法给自己定位,似乎是懂了,但真的碰上了又一言难尽.接下来有一些关于指针与数组的知识和例题讲解,来看看你对指针和数组到底有多了解吧! 指针与数组中的sizeof与strlen sizeof sizeof值关注占用空间的大小,单位是字节,不关注元素的类型,是一个操作

  • C语言指针教程示例详解

    目录 指针 内存 指针类型 指针运算 二级指针 指针数组 指针 指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作.另外,通过指针可以更便捷地操作数组.在一定意义上可以说,指针是 C 语言的精髓. 概念解释就不去搬原定义了,又臭又长不好理解,精炼两点就是: 1.指针是内存中的一个最小单元的编号,也就是地址: 2.平时我们说的指针,通常是指指针变量,用来存储内存地址的变量 也就是说:指针就是地址,口语中指针通常是指针变量 内存 要搞明白指针首先要搞

  • Windows系统中搭建Go语言开发环境图文详解

    目录 1.Go语言简介 2.安装Git 3.Go 工具链(编译器)安装 3.1.环境变量GOROOT 3.2.环境变量GOPATH 3.3.Go常用命令 4.包管理 4.1.go module 4.2.gopm 5.编写Go语言代码的IDE或编辑工具 5.1.基于VSCode的Go开发环境 5.1.1.安装VSCode 5.1.2.安装插件 5.1.3.常用配置 5.2.GoLand 5.3.Vim 5.4.其他Go代码编写工具 6.Go语言学习资料分享 本文详细讲述如何在 Windows 系统

  • C 语言指针概念的详解

    计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用4个字节,char 占用1个字节.为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号.身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节. 下图是 4G 内存中每个字节的编号(以十六进制表示): 我们将内存中字节的编号称为地址(Address)或指针(Pointer).地址从 0 开始依次增加,对于 32 位环境,程序能够使用的内存为 4GB,最小的地址为 0,最大的地址为 0XF

  • 图文详解go语言反射实现原理

    Go反射的实现和 interface 和 unsafe.Pointer 密切相关.如果对golang的 interface 底层实现还没有理解,可以去看我之前的文章: Go语言interface底层实现 , unsafe.Pointer 会在后续的文章中做介绍. (本文目前使用的Go环境是Go 1.12.9) interface回顾 首先我们简单的回顾一下interface的结构,总体上是: 细分下来分为有函数的 iface 和无函数的 eface (就是 interface{} ); 无函数的

  • C语言中二级指针的实例详解

    C语言中二级指针的实例详解 用图说明 示例代码: #include <stdio.h> int main(int argc, const char * argv[]) { // int a = 5; int *p1 = &a; //-打印地址-----地址相同--------------- printf("&a = %p\n", &a);// printf("p1 = %p\n", p1);// int **p2 = &p

  • C语言中枚举与指针的实例详解

     C语言中枚举与指针的实例详解 总结一下, 定义枚举,用typedef enum关键字, 比如 typedef enum{Red,Green,Blue} Color3; 枚举到数值的转换,如果没有指定代表数值就是从0开始算, 比如 Color3 c=Red; printf("%d",c);会显示0, 除非指定 如typedef enum{Red=3,Green=5,Blue=10} Color3; 关于类型指针的定义, 定义的时候在变量名左边加*代表此变量只是一个空指针而已, 若需要赋

  • C语言中 值传递和指针传递实例详解

    C语言中 值传递和指针传递实例详解 在C语言中,函数的参数和返回值的传递方式有两种:值传递和指针传递. 值传递和指针传递初学者总会有一种朦胧的感觉,所以建议把指针传递的概念摸透,才能熟练应用. 值传递示例:x其实是n的一份临时拷贝,所以并不会改变n的值. #include <stdio.h> #include <windows.h> void Fun(int x) { x = 1; } int main() { int n = 2; Fun(n); printf("%d\

随机推荐