C语言犄角旮旯的知识之不一样的指针

简介: C语言犄角旮旯的知识之不一样的指针

目录


指针的本质

指针的分类

野指针

空指针

其他指针

字符串指针

数组指针与指针数组

函数指针

二级指针与多级指针


正文


指针的本质


大家觉得指针的本质是什么呢,其实就是一个地址而已,指针这个词对于初学C语言的提醒来说,可能不是特别友好,其实大家换成地址,就好理解了。指针本质就是一个地址,每个地址对应着一个数值,对地址取这个值,便是把这个值取出来了。这样说,还是好理解了吧。


指针的分类


野指针


野指针是一个指向未知(undefine)、不确定的地方的指针。

未知的、不确定的地方:可能存在,可能不存在。

并且指向的地方,可能可以访问,可能不可以访问。


对野指针的访问会有什么后果呢?

       可能可以访问,可能不能访问(导致非法的内存访问)

         

       非法的内存访问:

           不存在的地方,你去访问。

           存在但不能读,但是你去读了。

           存在但不能写,但是你去写了。

     

       非法的内存访问会导致:segment fault(段错误),系统会把你这个进程给杀掉(kill掉)


int *p;//定义一个指针变量,你不赋初值,不代表p没有值,相反p一定有一个值,

        //只不过这个值是多少,不知道。


int *p;

int a; -->p为一个野指针

p = &a;//p不是一个野指针,指向了一个确定的地方


所以我们一般不建议用以上写法,我们建议在定义指针时,就给其赋值,避免成为野指针。如下:


int a;

int *p = &a; //<====>int *p; p = &a;


空指针


空指针


空指针是指向一个空的(NULL)指针。但空指针是野指针吗,显然不是。空指针不是一个野指针,但是空指针指向的地方一定是不能访问的。

对空指针访问会有什么后果呢,答案是出现“段错误。段错误也是使用指针时最常出现的错误。

其他指针


这里的其他指针,指的是定义正确,不是野指针与空指针的指针,如数组指针,函数指针等,我们一一介绍。


字符串指针

字符串与指针

   1.字符串

       字符串:一串字符,“多个字符”

 

       单个字符,c语言有专门的类型:

           char/unsigned char

       单个字符,保存的是字符的ascii码

 

       c语言中有没有字符串类型?没有,c语言中的字符是通过char *(字符指针)来实现的。

         

           字符串:用一组连续的地址空间来依次存储每个字符。并且要访问它的话,要通过char*.

   字符串就是一串字符,0个或者多个字符,并且约定以'\0'结束(ASCII码为0的字符)

   ’\0‘标志着字符串的结束。

 

   我们只需要知道字符串的首地址(char *),就可以访问所有字符了。

   so,char* 就可以描述一个字符串(保存的是字符串的首地址)

       1.1字符串常量 const char *

           不可以修改的字符串,只能读。 (存放在.rodata区域)

           如:在C代码中,是用“”引起来的都是字符串常量

           eq:

               char *p = "abc";

               p是一个字符指针,指向'a'的地址,保存'a'的地址;

               “abc”:字符串常量

               *p: 代表它指向的对象 'a', ’a‘没有左值,不可以被修改,'a'有右值

               printf("%c",*p);

               *p = 'A';//段错误  非法的内存访问

             

               p + 1 保存的是字符b的地址

               p + 2  保存的是字符c的地址

               p + 3  保存的是'\0'的地址

             

               p = "123"//没有问题的,p是一个变量,有左值,有右值。

       2.2 字符串变量

           字符串变量?可以修改的字符串,可读可写。

     

           eq:

               char s[5] = {'a','b','c'};

               char *p = s;//p保存的是&s[0] ,'a'的地址

               *p 代表的是它指向的对象 s[0],有左值也有右值

               *p = 'A';

           eq:

               char s[5] = {"abc"};

               ==>

                   s[0] = 'a';

                   s[1] = 'b';

                   s[2] = 'c';

                   s[3] = '\0';

                   s[4] = 0;

               char s[5] = {"abc"};

               char *p = s;

               *p = 'A';没有问题的。

           ==》 S是一个数组,如果数组是一个全局变量,s保存在.data区域【全局变量和静态变量(static)】;

           如果说数组是一个局部变量,s保存在栈空间,所以,数组s无论保存在哪里,s都是可以被修改的。


数组指针与指针数组


指针数组和数组指针:

 

   数组指针是什么? B

       A 数组 B指针  

       数组指针就是一个指针,指向一个数组的指针。

       函数指针就是一个指针,指向一个函数的指针。

       int (*p)[4] ==>int[4] *p  -->数组指针

       p是一个指针,指向int[4]

       p + 1 迈过了16个字节。

     

       eq:

           char (*p)[3] 数组指针 ==》char[3] *p

           p + 1 迈过了3个字节

         

   指针数组:

       指针数组是什么? B

           A 指针  B 数组

       指针数组是一个数组,只不过数组元素都是指针。

       int *p[4] // int* p[4]

       p是一个数组名,里面有4个元素,每一个元素都是一个指针,每一个指针都是指向一个int型。

       p是含有4个int*类型元素的数组


函数指针


有地址的对象,我们就可以定义一个变量,来保存它的地址。

       eq:

           int a;

           int *p = &a;

           int b[4];

           int (*p)[4] = &b;//p:数组指针

   函数也有地址,我们定义一个指针变量来保存函数的地址,这类指针,我们称为函数指针。

 

   1.什么是函数指针?

       函数指针就是一个函数的地址,

       函数指针变量就是一个指针变量,只不过它指向了一个函数。

     

   2.函数指针如何定义?

       指针定义的语法:

           指向的类型 *指针变量名

     

       函数的类型在c语言中如何描述?

           返回值的类型 (参数类型列表)

           eq:

               int sum(int a, int b)

               {

             

               }

               sum是一个带两个参数,第一个参数是int类型,第二个参数也是Int类型,返回值是int类型的函数。

           typeof(sum):

               int (int,int)

           如果要定义一个指针p,来保存sum的地址;

           typeof(sum) *p;

           int (int,int)*p; ==> int (*p)(int, int)

           p = ∑

           p = sum;

         

           eq:

               int find_max(int *b, int n);

               定义一个指针p,保存find_max的地址

               typeof(find_max) *p;=> int (int *, int) *p//编不过去

               =》int (*p)(int*, int);

             

           函数指针定义的语法:

               指向函数的返回值类型 (*函数指针变量名)(指向函数的参数类型列表)


   3.如何获取一个函数的地址?

       1.& 取地址符

           eq:

               &abc

       2.函数名

           在C语言中,函数名本身就是一个地址,函数的地址。

           eq:

               void abc(int b[],double f) -->abc函数名

                   typeof(abc) *p = void(int[],double) *p = void (*p)(int[],double)

                   p = &abc

                   p = abc

                 

   4.如何通过函数指针去调用函数呢?

       1,普通的函数调用

           函数名(实参表达式列表);

           eq:

               find_max(a,4);

         

               p = &find_max;//定义了一个函数指针变量p

               p = find_max;//函数名本身就是一个地址

               *p= *&find_max = find_max

             

               *函数指针 ==》 指向的函数

                   eq:

                       *p= *&find_max = find_max

 

       2.通过函数指针来调用函数:

           (1)

               (*函数指针)(实参表达式列表)

                   int (*p)(int, int)

                   eq: (*p)(3,4)

           (2)

               函数指针名(实参表达式列表)

                   p(a,4) = find_max(a,4)

     

   5.为什么需要函数指针?

       函数指针是用来实现callback(回调)的

           call me back

       回调?

           回过头来调用,我现在不用。

           通过函数指针保存一个函数的地址,等需要调用时我再来通过函数指针来调用。--》回调

           eq:

           int sum(int a, int b)

           {

               return a + b;

           }


           int main()

           {

               int (*p)(int,int);//定义了一个函数指针

               p = ∑

               int a;

               a = sum(3,5);

               printf("%d\n",a);

             

               a = (*p)(10,12);

               printf("%d\n",a);

               a = p(10,10);

               printf("%d\n",a);

           }


二级指针与多级指针


二级指针和多级指针(---->就是一个指针)

   int a;

   定义一个指针变量,来保存a的地址。

       typeof(a) *p; //p是一级指针

       int *p;

       p = &a;//int *p = &a;

       p本身也是有地址的,我们可以定义一个指针变量p2来保存p的地址。

       typeof(p) *p2;

       int** p2; //p2是2级指针

       p2 = &p;

     

       p2本身也是有地址的,我们可以定义一个指针变量p3来保存p2的地址。

       typeof(p2) *p3;

       int*** p3;//p3是3级指针

       p3 = &p2;

     

       p3本身也有地址,我们定义一个指针变量p4来保存p3的地址。

     typeof(p3) *p4;
        int**** p4;//p4是4级指针
        p4 = &p3;
        ...
            p = &a;
            p2 = &p;
            p3 = &p2;
            p4 = &p3;
        int main()
        {
            int a = 1024;
            int *p, **p2,***p3, ****p4;
            p = &a; //1024
            p2 = &p; //1024
            p3 = &p2; //1024
            p4 = &p3; //1024
            => *p,**p2,***p3,****p4.
        }


       *p = *&a = a;

       *p2 = *&p = p

       **p2 = **&p = *p = *&a = a;

       ***p2 = ***&p = **p = **&a = *a;//ERROR :a的值不是一个地址

     

       *p3 = *&p2 = p2

       ***p3 = ***&p2 = **p2 = **&p = *p = *&a = a;

       ****p4 = ****&p3 = ***p3 = ***&p2 = **p2 = **&p = *p = *&a = a;

相关文章
|
2月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
186 9
|
2月前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
65 7
|
2月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
124 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
3月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
3月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
72 1
|
3月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
228 3
|
3月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
3月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
3月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
3月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
276 13

热门文章

最新文章