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;

相关文章
|
1月前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
35 1
|
15天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
41 0
|
14天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
11 2
|
14天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
14天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
21天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
20天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
21天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
21天前
|
C语言
C语言指针(3)
C语言指针(3)
11 1
|
21天前
|
C语言
C语言指针(2)
C语言指针(2)
12 1