引言:本篇再一次写到指针,学过c语言的都知道,指针是初学c语言时候遇到的一个比较难搞的知识点。你尽管可以想的简单,但是其实如果去用的话,没有一个更加深入的理解,那么后续的学习到数据结构就会艰难无比。


指针?c语言的灵魂所在。本篇还是会结合数组来讲,当指针和数据结合起来的时候就会变得奇妙无比。提高一点点的难度,记得第一次也写过c语言的指针,只不过相对简单。第一篇c语言指针的链接如下

c语言指针的有关总结

深入理解c语言指针与数组

  • c语言指针与数组
    • 一: 指针的理解与操作
      • 1:指针与指针变量?
      • 2:二级指针,多级指针,指向指针的指针?
        • 指针占用空间?难道会同指向的类型变量的大小一直一致吗?
      • 3:定义指针的*号与后面引用p取的 *号一样吗?
    • 二: 数组理解与操作
      • 1:定义初始化
      • 2:给数组赋值
        • 1:给整形数组赋值
        • 2:给字符型数组进行赋值
      • 2:一维数组?二维数组?三维数组?
    • 三: 指针与数组的复杂纠葛
      • 1:指针与数组
        • (1)指向一维数组
        • (2)指向二维数组
      • 2:指针数组
      • 3:数组指针
    • 四:给你一些相关的内容以及遇到的问题

c语言指针与数组

一: 指针的理解与操作

1:指针与指针变量?

指针是什么?以及指针地址的概念?

指针就是地址,地址就是指针。指针变量可用于存放地址。

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
  存放地址的变量称为指针变量。指针变量是一种特殊的变量,它不同于一般的变量,一般变量存放的是数据本身,而指针变量存放的是数据的地址。

将指针的等同于指针变量是不严格的说法,指针并不是存放地址,指针变量才可以存放地址。我们从概念上区分。但是可能会通常会把指针变量也简化称之为指针了,但是我们需要知道,实际上并不等同。
然后我们简单写代码也可以验证这个说法

#include<stdio.h>
#include<windows.h>
int main()
{int a = 0;int *p = &a;//定义了指针变量存放了a的地址printf("the address of a is %d\n",&a);printf("the value of p is %d or %p\n",p);system("pause");}

2:二级指针,多级指针,指向指针的指针?

这边的指针大家在代码中就理解为指针变量就可,这样严格一些就不会弄混。
我们定义一个指针变量,既然是一个变量,那肯定需要空间,或者叫内存空间,既然是占用了内存空间,那必然会有地址,既然是有地址,我们必然可以定义另一个指针来存放该指针变量的地址。所以可以称之为双重指针。
下面展示一些 内联代码片

#include<stdio.h>
#include<windows.h>
int main()
{//指向指针的指针int *p1 = NULL;int a1 = 6;p1 = &a1;int **p2 = &p1;printf("the value of address of a is %d\n",&a1);printf("the value of p1 is %d\n",p1);printf("the address of p1 is %d\n",&p1);printf("the value of p2 is :%d\n",p2);printf("the value of *p2 is :%d\n",*p2);printf("the value of **p2 is %d\n",**p2);printf("the value of address of p2 is %d\n",&p2);system("pause");}

指针占用空间?难道会同指向的类型变量的大小一直一致吗?

当然不是啦!

加一些代码,分别定义两个指针,一个指向charl类型,一个指向int类型,下面输出两者各占的字节数。

3:定义指针的*号与后面引用p取的 *号一样吗?

不一样啊!

int *p 这边的 *号是作为了区分指针与一般变量的符号,定义这边只说明了该变量是指针。而你在后面所用到的 *p我们可以认为是取该指针指向地址处得值得含义。上边的代码也有说明打印。所以这个也算作是一个容易混淆的区分点。

下面展示一些 内联代码片

#include<stdio.h>
#include<windows.h>
int main()
{//指向指针的指针char a ='c';char *p =&a;int *p1 = NULL;int a1 = 6;p1 = &a1;int **p2 = &p1;printf("the value of address of a is %d\n",&a1);printf("the value of p1 is %d\n",p1);printf("the address of p1 is %d\n",&p1);printf("the value of p2 is :%d\n",p2);printf("the value of *p2 is :%d\n",*p2);printf("the value of **p2 is %d\n",**p2);printf("the value of address of p2 is %d\n",&p2);printf("the size of a is %d\n",sizeof(a));printf("the size of a1 id %d\n",sizeof(a1));printf("the size of p is %d\n",sizeof(p));printf("the size of p1 is %d\n",sizeof(p1));system("pause");}


可以看到两个指针都占四个字节,虽然指向不同的类型。所以说指针所占的内存数和指向的数据类型是没有关系的。


二: 数组理解与操作

1:定义初始化

普通的一维数组也就没什么太大的区别了,要说区别话,也可能只是类型的问题。

(1)初始化一维数组
一写可以尝试的初始化,这里就举例数值型和字符型

#include<stdio.h>
#include<windows.h>
int main()
{int a[] = {};int a1[] = {1,2,3,4};int a2[5] = {};int a3[5] = {1,2,3,4,5};char s1[] = {"Hello Everyone"};char s2[] = {'a','b','c','\0'};char s3[10] = {'a','b','\0'};char s4[10] = {"Hello "};//printf("%d",a[0]);system("pause");}

(2)初始化二维数组
我们还是以数值型和字符型举例

#include<stdio.h>
#include<windows.h>>
int main()
{int array[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};int array1[][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16},{17,18,19,20}};int array2[][5] = {};system("pause");char words[][4] ={{'a','b','c','\0'},{'d','e','f','\0'}};char words_1[][6] ={"boy","hello","yes","right","what"};char words_2[][4] = {};char words_3[3][4] ={{'a','b','c','\0'},{'e','f','g','\0'},{'i','j','k','\0'}};
}

2:给数组赋值

谈到给数组赋值,在一些老版本说明中,比如一维数组是必须要有常量来规定初始化的数组的大小的,就算是二维数组也要至少指定列。但是c语言版本c99后好像是可以动态赋值了,意思是你可以定义一个n,然后int[n],n需要输入即可,但是在我的版本里面这是万万不行的。

1:给整形数组赋值

我们还是按照常规的方法给数组赋值,举一个给整型二维数组赋值的例子。

#include<stdio.h>
#include<windows.h>
int main()
{int arr[3][4] = {0};for(int i =0;i<3;i++){for(int j =0;j<4;j++){scanf("%d",&arr[i][j]);}}for(int i =0;i<3;i++){for(int j =0;j<4;j++){printf("%d,",arr[i][j]);}}system("pause");}


赋值的时候一定要记得记得取地址,&,不加这个符号意味着你要改变地址,这怎么能让你随便改呢?

2:给字符型数组进行赋值

当然也可以通过函数赋值,也可以手动介入。

#include<stdio.h>
#include<windows.h>
int main()
{// int arr[3][4] = {0};// for(int i =0;i<3;i++){//     for(int j =0;j<4;j++){//         scanf("%d",&arr[i][j]);//     }// }//   for(int i =0;i<3;i++){//     for(int j =0;j<4;j++){//        printf("%d,",arr[i][j]);//     }// }char name[10];scanf("%s",name);printf("the value is:[%s]",name);system("pause");}

这个是空格结束的
但是可以呢,如果输入的大于定义的长度呢?你看竟然也输出来了。???


还可以通过gets()函数

#include<stdio.h>
#include<windows.h>
int main()
{char name[10];gets(name);printf("the value of name is %s",name);system("pause");}


fgets()函数,这个也是赋值

#include<stdio.h>
#include<windows.h>
int main()
{char name[10];//name 字符串 ,10 长度, stdin默认输入设备fgets(name,10,stdin);printf("the value of name is %s ",name);system("pause");}


当然还有其它的赋值方法,就不再举例了。
当然二维字符数组也可以赋值,道理是一样的,举例一个比较简单的赋值方法,你比如。

#include<stdio.h>
#include<windows.h>
int main()
{char str[3][20];strcpy(str[0],"abcccc")strcpy(str[1],"asnksnaks");strcpy(str[2],"shdjkhdkjdk");printf("%s\n",str[0]);system("pause");}

这个还是很简单的。当然你也可以使用for循环进行赋值

那么举例一个使用for循环给二维数组赋值

#include<stdio.h>
#include<windows.h>
int main()
{char str[3][20];//    strcpy(str[0],"abcccc");//或者用sprintf(str[0],"123");//    strcpy(str[1],"asnksnaks");//或者用sprintf(str[1],"456");//    strcpy(str[2],"shdjkhdkjdk");// printf("%s\n",str[0]);// system("pause");for(int i =0;i<3;i++){scanf("%s",&str[i]);}printf("%s",str[0]);system("pause");}

2:一维数组?二维数组?三维数组?

一维数组的化我们按照抽象出来的理解就是按照线性存储的方式罢了,二维的化也就是矩形,三维的化抽象出来也就是下面的这张图
什么?还有三维数组?

对啊,还有思维数组。不过只是未来理解,我们就讲到三维。
定义什么的就不需要赘述
其实你看啊,所谓的一维二维三维等等,只不过是抽象出来的概念。在内存中其实还是线性存放的。
就比如这样,下面一个二维数组。实际的存放方式是这样的。但是可能将其抽象化为矩形也是比较形象,不过我觉得,如果知道是线性的实际存放,在后面学习指针理解的化还是很有帮助的。

所以无论是多少维的数组,其在内存中的本质还是线性存放。

三: 指针与数组的复杂纠葛

1:指针与数组

指针可以配合数组干点什么事情呢?
我们定义的指针变量可以存放地址,那就可以存放数组的地址啊!

(1)指向一维数组

一个简单的运用

#include<stdio.h>
#include<windows.h>
int main()
{   char str[] = "I love you";char *target = str;int count = 0;while (*target++ !='\0'){   count++;/* code */// printf("%d",count);}printf("the total is :%d",count);system("pause");
}

就拿这一个说明

我们这边的target指针是指向数组的,明白了说也就是数组的首地址,就是字符I的首地址,初始化是这样,当我们给指针进行++的时候就会依次指向第二个以至于往后。取*号就是取地址处的值,ok,说明白了。

根本还有要理解指针是怎样指向的,以及怎样指向数组,这样就不会被反复套娃。


(2)指向二维数组

你看指向二维数组,我们这边形象化一下,你再理解一下数组名代表了什么?

打印输出数组名就会得到数组的首地址,也就是第一个元素的值。


要想搞清楚,那就打印验证

#include<stdio.h>
#include<windows.h>
int main(){int array[2][3] = {0};for(int i =0;i<2;i++){for(int j=0;j<3;j++){scanf("%d",&array[i][j]);}}printf("size of int is %d\n",sizeof(int));printf("the add of array pointed is %d\n",array);//我们这边按照十进制将地址打印出来,是整个数组的首地址printf("the value of *array pointed is %d\n",*array);//可以认为取到嵌套的一维数组的地址printf("the value of **array is %d\n",**array);//可以认为取到存放一维数组的值printf("the value of *(array+1) pointed is %d\n",*(array+1));printf("the add of array+1 pointed is %d\n",array+1);system("pause");/*输出打印后通过分析可得,array是指向五个包含元素的数组的指针*/
}
/*
如何理解二维数组呢?二维数组根本还是在内存中按照一维数组存放的。可以认为是嵌套。
*/


写不动了,就不再举例了。我们来看搞脑子的有趣的知识点。

2:指针数组

你可能不怎么用,我承认对大一的同学们可能就离谱。什么?还有这玩意?

必要的时候没图就理解不了啊!小甲鱼的图图,我带来了。

为什么这就是一个指针数组呢?而不是数组指针?

[]的优先级别高于*,所以先结合p后结合*。

指针数组是一个数组,每个数组元素存放一个指针变量

可以干啥?可以这样做

#include<stdio.h>
#include<windows.h>
int main()
{   //下面这个是指针数组char *p1[5] = {"every one can dream!","i think i can successful","dont care it ,just do it for your dream","how are you","believe yourself"
};for (int i =0;i<5;i++){printf("%s\n",p1[i]);}system("pause");}


你可能产生一种不可理解的意识,那就是字符串怎么能赋值给指针呢。但是并不是这个意思。
我们这样理解,声明了一个字符指针后,并用字符串常量的第一个字符的地址赋值给指针变量p1[i]。

3:数组指针

继续套娃

那么数组指针是什么?

可以看到p和*加了括号,所以会优先结合

数组指针就是指向数组的指针

来一段简单的代码

//下面演示数组指针,指向数组的指针,不要认为其指向地址,而是指向整个数组
#include<stdio.h>
#include<windows.h>
int main()
{int temp[] ={1,2,3,4,5};int (*p2)[5] = &temp;int i;for(i =0;i<5;i++){printf("%d\n",*(*p2+i));}system("pause");
}


问题来了,既然p2是指针,那么*p就·代表了取值,为什么要取 * 呢?

p2是指向整个数组,我们可以这样理解,进行一层 * 可以认为其取到数组第一个元素的首地址,再次*可认为取值。ok

四:给你一些相关的内容以及遇到的问题

套娃
给几个代码

/*使用指针的方法将最大值保存到变量a中去,最小值保存到变量b中去*/
#include <stdio.h>void ff(int *p1, int *p2) {//把实参的地址内容传递过去赋值的过程int a;//和main函数中的a不一样的a = *p1;//将p1地址上的值传给a;
//  printf("%d", &a);*p1 = *p2;*p2 = a;
}int main() {int a, b;int *p_1, *p_2; //定义指针型变量指向int类型的变量scanf("%d %d", &a, &b);p_1 = &a; //将地址附值给p_1,p_2;p_2 = &b;printf("%d,%d\n", &a, &b);if (a < b) {ff(p_1, p_2);}printf("最大值为%d,最小值为%d", a, b);return 0;
}
#include<stdio.h>
#include<windows.h>
int main()
{   //初始化两个指针开始指向空int *p1 =NULL;int *p2 =NULL;int *p3 =NULL;int a =6,b =8,c =10;p1 =&a;//代表p1指针指向a的地址p2 =&b;p3 =&c;//你可以先打印*p1/*p2代表了什么,其实这次再取*的话,和指针定义的*不一样,代表取取指针指向地址处的内容// eg:printf("the value of a is %d\n",*p1);printf("the address of a is %p\n",p1);//打印地址直接就%p//交换值可以取值直接交换// eg:*p1 = *p2;printf("this time ,the value of a is %d\n",a);//?试试地址交换?p1 = p3;printf("the value of a is %d\n",a);//打印输出你只会发现值交换才是有效的,用指针只是指针的指向发生了改变printf("the value of pointer p1 is %d",*p1);system("pause");
}
#include<stdio.h>
#include<windows.h>
int main(){int array[2][3] = {0};for(int i =0;i<2;i++){for(int j=0;j<3;j++){scanf("%d",&array[i][j]);}}printf("size of int is %d\n",sizeof(int));printf("the add of array pointed is %d\n",array);//我们这边按照十进制将地址打印出来,是整个数组的首地址printf("the value of *array pointed is %d\n",*array);//可以认为取到嵌套的一维数组的地址printf("the value of **array is %d\n",**array);//可以认为取到存放一维数组的值printf("the value of *(array+1) pointed is %d\n",*(array+1));printf("the add of array+1 pointed is %d\n",array+1);system("pause");/*输出打印后通过分析可得,array是指向五个包含元素的数组的指针*/
}
/*
如何理解二维数组呢?二维数组根本还是在内存中按照一维数组存放的。可以认为是嵌套。
*/
#include<stdio.h>
#include<windows.h>
//指针数组
int main()
{char *cBooks[] = {"Cease to struggle and you cease to live","Time ca heal a broken heart,but it can also break a waiting heart","the fox changes his skin but not his habbits","Time is but a river flowing from our past"};char **jgdabc;char **jgdabc_loves[4];jgdabc_loves[0] = &cBooks[0];jgdabc_loves[1]  = &cBooks[1];jgdabc_loves[2] = &cBooks[2];jgdabc_loves[3] = &cBooks[3];printf("%d\n",jgdabc_loves[0]);printf("%d\n",*jgdabc_loves);printf("%s\n",*jgdabc_loves[0]);printf("%c\n",**jgdabc_loves[0]);printf("%c\n",**jgdabc_loves[1]);system("pause");}

这边请自行运行并思考,专注指针的要点,以及指向指针的·指针的含义。


原创不易,未经许可禁止抄袭转载。
–点击访问主页jgdabc

c语言指针与数组的深入理解相关推荐

  1. c语言指针和数组的联系

    c语言指针与数组 **一.指针与一维数组** 1.一维数组的存储方式 2. 对一维数组名的理解 3. 数组下标和指针的关系 4.一位数组名与取数组首地址的区别 **二.指针与二维数组** 1.二维数组 ...

  2. C语言中指针与数组的区别,C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[ ...

  3. 指针c语言与数组,C语言指针与数组

    C语言指针与数组 数组的下标应该从0还是1开始? 我提议的妥协方案是0.5,可惜他们未予认真考虑便一口回绝    -- Stan Kelly-Bootle 1. 数组并非指针 为什么很多人会认为指针和 ...

  4. c语言指针数组课件,C语言指针与数组教程课件.ppt

    C语言指针与数组教程;教学要求;本章主要内容;引子;#include void swap ( int x, int y ) { printf("调用时:x地址为:%p, 值为:%d\n&qu ...

  5. C语言 指针和数组区别 - C语言零基础入门教程

    目录 一.前言 二.指针和数组区别 1.通过 sizeof 获取大小 a.计算数组大小 b.计算指针大小 2.指针和数组赋值方式不同 a.指针赋值 b.数组赋值 3.指针是指针变量,数组是指针常量 三 ...

  6. c语言指针数组 难点总结,C语言指针与数组的难点分析.pdf

    C语言指针与数组的难点分析,c语言指针数组,c语言二维数组指针,c语言指针数组初始化,c语言函数指针数组,c语言数组与指针,c语言结构体数组指针,c语言指向数组的指针,c语言字符串数组指针,c语言数组 ...

  7. C语言指针和数组的天生姻缘

    指针和数组的天生姻缘 以指针的方式来访问数组 指针和下标访问数组的本质 数组和指针并不是相等的 从内存角度理解指针访问数组的实质 指针和数组类型的匹配问题 以指针的方式来访问数组 数组元素使用时不能整 ...

  8. C语言指针与数组之间的恩恩怨怨

    很多初学者弄不清指针和数组到底有什么样的关系.我现在就告诉你:他们之间没有任何关系!只是他们经常穿着相似的衣服来逗你玩罢了. 指针就是指针,指针变量在32 位系统下,永远占4 个byte,其值为某一个 ...

  9. C语言指针,数组,函数

    下面6个声明语句分别声明的是什么? 如果不能快速地分清,我们就来一起来学习一下.首先我们先了解一下标识符,标识符是标识某个实体的一个符号,用于给变量.常量.函数.语句块等命名.上面6个声明语句中有6个 ...

最新文章

  1. HDOJ 1098 Ignatius's puzzle
  2. Linux - Nginx安装
  3. Java构造器、静态对象、非静态对象等的初始化顺序
  4. python进阶九_网络编程
  5. MySQL InnoDB Cluster安装
  6. .NET Core Community 首个千星项目诞生:CAP
  7. java安全(二):JDBC|sql注入|预编译
  8. C++ const成员变量和成员函数
  9. 今日上新:两个图像领域的现金奖励实时竞赛
  10. Windows Server 2003成员服务器基准用户权限分配策略
  11. LeetCode刷题系列(一)把回溯算法框架将给爷爷奶奶听
  12. 10个优秀的思维导图软件,各种需求都能满足!!!
  13. 不懂Web基本原理怎么能学好爬虫。( 二、Web服务器工作原理)(爬虫、反爬虫、服务器、客户端、网络协议 )
  14. gltf 2.0快速入门
  15. uni-app之uniCloud(一)
  16. 图片+css实现波浪
  17. iOS_异常堆栈报告分析
  18. 前后端分离开发下的权限管控 :SpringSecurity 框架
  19. CICD使用阿里云 云效实现自动发布代码
  20. ad设置塞孔_干货丨PCB线路板过孔堵上,到底是什么学问?

热门文章

  1. matlab能量谱分析检验,一种基于短时能量检测和频谱特征分析的地震波预警方法...
  2. 对接银联商务微信公众号支付遇到的坑
  3. 智慧农业解决方案-土壤速测仪
  4. 读书笔记 PCG in Games 程序化内容生成2 基于搜索的方法
  5. Android面经:入职网易的那一天,我哭了,kotlin语法印章类
  6. 江山代有才人出,各领风骚数百年
  7. 生信漫谈如何利用MEGA7构建系统进化树
  8. 应广单片机PMS150/PMC150/PMS150C消费类单片机
  9. 克拉美-罗下界(Cramer-Rao Lower Bound,CRLB)
  10. 通过GRUB2打造多系统混合安装U盘