[C语言] 想学会用指针吗?

2019-08-03  本文已影响0人  入梦瞌睡

目录

1.本文主要内容

2.基础知识讲解

3.拓展延伸

4.实际应用

5.总结

0.前言

  • 上一篇文章《部分经典排序算法详解(有图解)》中,
    我们通过图解的方式,详解了三种经典的排序方法

  • 本文主要讲解C语言的最后一个内容,
    也是被称为“C语言的灵魂”的内容——指针

1.本文主要内容

2.基础知识讲解

2.1 指针的基础概念

(1)指针能解决哪些问题?
         指针能解决跨区域问题
      (即不同作用域、不同代码块之间的数据交互)

(2)指针是如何解决这些问题的?
         指针能够通过自身指向的地址,来操作该地址所存储的值
         以此达到跨区域的数据交互问题

2.2指针的语法定义

2.2.1基本定义方法:
int *p;

其中,变量p即为一个整型指针变量

Int *的意思就是该指针只能指向一个整型变量,
该p指针变量的内存空间只能存储一个整型变量的地址

2.2.2基本使用方法:
int a =10;
int *p = &a;//p指向a的地址
printf("%d\n",*p);//输出p指向的地址的值

这里从第二行开始对一些重要的细节进行解释:

总结:

  • “&” 表示取变量的地址

  • 指针变量中使用星号* 表示变量p是指针
    其他情况下指针变量前加星号* 表示取变量p所指向地址中存储的值

2.2.3指针与数组:

指针与数组有着不少联系
可以使用一个指针指向数组的首地址,然后通过指针来控制、访问数组:

int *p;
int a[20] = {};
p = a;
printf("%d",p[1]);//输出数组a的第二个元素
printf("%d",p+1);//输出数组a的第二个元素

我们来分析一下细节部分:

  • 因为数组a的变量名为a,该变量名所代表的就是该数组的首地址,因此可以把a赋给p,意思就是将数组a的首地址赋给指针p

  • 当p指向数组a之后,p[i]则可以用来表示a[i](效果相同)

  • 由于是int型指针变量,设数组a的首地址为0x100
    则p+1的含义是0x100 +1*4 = 0x104,实际上 p+1与p[1]同效果

3.拓展延伸

3.1关于指针的一些研究

3.1.1语法相关注意事项

看看是否能区分一下的语句的含义:

printf("%p",score);输出的是第一个元素的地址
printf("%p",score+1);输出的是第二个元素的地址
printf("%d",*(score+1) );输出的是第二个元素的值
printf("%d",*score +1 );输出的是第一个元素的值+1
printf("%d",*score++);输出的是?
注意:
  • *score++相当于( *score)++,星号优先级更高
    *(score++)则是先地址++,再与星号结合
    因此printf("%d", *score++);输出的是 *score,
    语句结束后 *score会+1

再看看一下语句:

char * const p  

char const *p 

const char *p  

总结:

  • char * const p
    p是一个char型指针,const修饰的是p,p不允许改变
    该指针p是常量,不允许修改

  • char const *p 与 const char *p
    p是同一种char型指针,const修饰的是char
    指针指向的字符被看作是常量,不允许修改

 

3.1.2其他注意事项

(1) 指针必须要指向具体的存储空间,才能赋具体的(非地址)值
int *p;
*p = 10; //会报错

由于p并未指向一个具体的内存空间,使用*p并对其赋值肯定会报错

解决办法:

①将其他值的地址赋给p,就可以使用*p了

②使用malloc()与realloc()自行申请内存空间

(2)使用malloc()与realloc()申请内存空间方法

语法:

int* p;
p = (int*)malloc(10 * sizeof(int));
p = (int*)realloc(p,20*sizeof(int));
  • 第二句语法可以分配10个连续的大小为4个字节的空间
    (64位中,整型空间为4个字节)

  • 第三句可以为p重新分配一个大小为20个4个字节的空间
    其中realloc中的p就是malloc的接收对象

  • 使用realloc的前提是,必须先用malloc开辟一段空间

4.实际应用

4.1让函数改变多个参数

一般情况下,我们都会通过返回值来把函数中修改后的值返回出来
由于返回值只能返回一个值
如果需要同时修改多个参数,返回值就无法满足我们

void add(int a,int b){
      a++;
      b++
}
void main(){
  int m=0,n=0;      
  add(m,n);
}

我们都知道,上面这种情况下,m与n的值最终是不会变的

调用add()函数时,m与n将它们的值传给形参a、b,
形参的操作并不会影响实参m、n,故最后m、n的值并不会改变

想要解决这个问题,就需要使用指针:

void add(int *a,int *b){
      *a++;
      *b++
}
void main(){
  int m=0,n=0;      
  int *p1 = &m;
  int *p2 = &n;
  add(p1,p2);
}

实参传给形参的是需要操作的变量的地址,
形参作为指针,会通过地址去操作变量
以此来操控我们的目标变量的值

4.2定义链表的结构

链表相当于是通过指针来连接的

typedef struct Node{
    int data;
    struct Node* next;
}Node;

链表中存在一个个的节点,这些节点都包括一个存放数据的数据域,
以及存放下一个节点的地址的指针变量next

链表的优缺点:

  • 优点:增加数据、删除数据十分方便,
    只需要改变指针的指向即可完成
  • 缺点:查找不方便,每次查找往往都伴随着大量遍历

数组的优缺点:

  • 优点:访问某个特定位置的元素十分方便
  • 缺点:增加、删除元素极为麻烦

5.总结

(1)本文讲解了有关指针的基础知识、使用方法以及注意事项,希望各位读者能从中有所收获

(2)指针是一个十分灵活的工具,关键就是:
          要理解为何要使用指针,以及指针能做些什么
其实明白了这里两点后,就能基本知道指针该如何使用了(指概念理论方面),剩下只要多练习就可以完全把握指针了

(3)指针看起来很难,但是只要明白其本质,并多多练习,就可以掌握,这里尤其是推荐:多编写一些与链表有关的项目 ,笔者觉得对于新手来说,练习链表的使用,是熟悉指针的最好方法之一。

上一篇 下一篇

猜你喜欢

热点阅读