C语言学习笔记五、一维数组、二维数组、一级指针、二级指针、数组指针、指针数组

五、一维数组、二维数组、一级指针、二级指针、数组指针、指针数组

1.一维数组

①. 定义:数组就是某种数据类型变量的集合,存放在一块连续的内存上。

②. 作用:方便定义相同数据类型的变量。

③. 数组框架:元素的数据类型 数组名(元素个数)

    例如: int num30  <=>  int num[30]。
    其中,元素的数据类型有:int char float...int *, char *, struct ....等
    注意:元素个数必须是正整数!!!

④. 数组的定义方式

1)int a[3];  //未初始化定义,定义了一个有3个元素的数组,数组的元素类型为:int,数组的成员                值为随机值
​
2)int a[3]={1, 2, 3}; //全部初始化定义,定义了一个有3个元素的数组,数组的元素类型为:                         int,数组的成员值为:a[0] == 1,  a[1] == 2,  a[2] == 3
​
3)int a[3]={1,2};   //部分初始化定义,定义了一个有3个元素的数组,数组的元素类型为:                          int,数组的成员值为:a[0] == 1,  a[1] == 2,  a[2] == 0
​
4)int a[]={1, 2, 3, 4, 5}; //不定长数组,必须初始化,定义了一个有5个元素的数组,数组的                              元素类型为:int,数组的成员值为:a[0] == 1,                                      a[1] == 2, a[2] == 3,a[3] == 4,a[4] == 5
​
5)
    int num;                //变长数组,不能初始化,定义时,num的值必须确定,
    scanf("%d", &num);        
    int a[num];             //定义了一个有num个元素的数组,数组的元素类型为:int;
                              如果要给数组赋值,需要一个一个赋值 。

⑤. 计算数组的内存大小

  数组的内存大小 == 数组元素类型所占字节数*元素个数
  例如:   int a[10];
          sizeof(a) == sizeof(int)*10 == 40;
          char b[10];
          sizeof(b) == sizeof(char)*10 == 10;

⑥. 访问数组元素

int a[5]={1,2,3,4,5};
    a[0]==1;
    a[1]==2;
    a[2]==3;
    a[3]==4;
    a[4]==5;   //数组元素最大的下标值等于元素个数-1

⑦. 数组名和数组的数据类型

1)数组名是数组首元素地址    //int a[5]; a==&a[0];
​
2)数据类型
    int a[3];   //数组a的数据类型是:int()[3];
                //数组a的元素类型是:int;

2.二维数组

①. 二维数组本质上也是一维数组,只是其元素数据类型为一维数组,所以叫二维数组。

②. 二维数组定义模型

小数组的元素类型 数组名[N][M]
//N:大数组的元素个数;
//M:小数组的元素个数;
//小数组的元素类型: int, char, float....
例如: int array[2][3] --》表示定义了一个二维数组array,它有两个元素类型为int()[3]的元素。

③. 二维数组的定义和初始化

1)int a[2][3]; //未初始化定义,定义了一个二维数组,该数组有两个元素,                                   元素类型为:int ()[3],它的值为随机值
​
2)int a[2][3]={{1, 2, 3}, {4, 5, 6}}; 
        //全部初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3],             它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4,                            a[1][1]==5, a[1][2]==6
​
3)int a[2][3]={1, 2, 3, 4, 5, 6}; 
        //全部初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3],             它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4,                               a[1][1]==5, a[1][2]==6
​
4)int a[2][3]={{1}, {4, 5}}; 
        //部分初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3],             它的小数组的元素值:a[0][0]==1, a[0][1]==0, a[0][2]==0, a[1][0]==4,                               a[1][1]==5, a[1][2]==0
​
5)int a[2][3]={1, 2, 3};
        //部分初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3],             它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==0,                               a[1][1]==0, a[1][2]==0
​
6)int a[][3]={{1, 2, 3},{4}}; 
        //不定长二维数组,定义了一个二维数组,该数组有两个元素,元素类型为:int()[3],              它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4,                               a[1][1]==0, a[1][2]==0
​
注意:int a[2][]={{1, 2, 3},{4}};//小数组的元素个数必须确定的,否则编译会报错!!!

④. 二维数组的大小

二维数组的大小 == 小数组的元素类型大小 *小数组的元素个数 *大数组的元素个数

== 大数组的元素个数*小数组的数据类型大小

⑤. 数组元素的访问

        int a[2][3]={1,2,3,4};  //把这种数组称之为两行三列的数组
​
        a[0][0]==1,  --》元素地址为:&a[0][0]
        a[0][1]==2,  --》元素地址为:&a[0][1]
        a[0][2]==3,
        a[1][0]==4,
        a[1][1]==0,  --》其余为赋值的元素默认值为0
        a[1][2]==0

3.一级指针

①. 概念:指针也是一种变量,指针变量是用来存储对应变量的内存地址的。

②. 如何定义一个指针变量

模型: 被存储变量的数据类型 *变量名
​
例如: int a;          //系统分配了4个字节内存,并把这块内存命名为a
      a = 100;        //把100转化为二进制存储到a这块内存
      int *p;         //系统分配了4个字节内存,并把这块内存命名为p
      p=&a;           //获取变量a的内存地址,把它转化为二进制存储到p这块内存

③. 怎么使用指针变量(解引用、取目标)

例如:
    int a= 100;
    int *p = &a;//--》int *p;  p=&a;
    *p = 200;  《--》  a=200
    printf(“*p:%d\n”, *p);  //%d==200;
    printf(“a:%d\n”, a);    //%d==200;

④. 指针内存大小:

 无论什么类型的指针在32位系统中占4个字节   //char *p==4; int *p1==4;
 无论什么类型的指针在在64位系统中占8个字节 //char *p==8; int *p1==8;

⑤. 指针加减--》内存地址加减

例如:
    int a = 0;
    int *p =&a;                 //假设a的地址为0x1000;
    p+1 --》 &a +1 == &a+1 *(sizeof(int))  //p+1 == 0x1000+1*4 == 0x1004
    
内存地址分为两部分:地址值和存储的对象
​
指针加减:和它存储对象的大小是有关系的
地址加减:和它存储对象的大小是有关系的
​
int 型指针+1 == int 型指针+1*sizeof(int)
int 型指针+2== int 型指针+2*sizeof(int)
​
char 型指针+1 == char 型指针+1*sizeof(char)
long long 型指针+1 == long long型指针+1*sizeof(long long)
​
int 变量地址+1 == int 变量地址+1*sizeof(int)
int 变量地址+2== int 变量地址+2*sizeof(int)
​
char变量地址+1 == char变量地址+1*sizeof(char)
long long变量地址+1 == long long变量地址+1*sizeof(long long)
​
​
注意:
    指针加减要考虑它存储对象的大小
​
    内存地址加减也要考虑它存储对象的大小
​
    内存地址包括两部分:地址值和存储的对象
​

⑥. 指针类型

int a=100;  a的数据类型是:int
            100的数据类型是:int
            &a的类型是:int *

int *p=&a;  p的数据类型是:int *
            p存储的对象类型为:    int
            &a 的类型:int *
            &p的类型:int **

 

⑦. 通用指针(万能指针)

作用:能合法存储任意类型变量的地址,但是不能直接解引用

#include <stdio.h>
#include <strings.h>
​
int main()
{
    unsigned int a =0x12345678;
    void *p2 = &a;
    
    //(unsigned int *)p2 把p2从viod *临时强制类型转换为unsigned int *(欺骗计算机)
    //此时(unsigned int*)p2+1==  (unsignedint*)p2+1*sizeof(unsigned int)
    
    printf("%x\n", *((unsigned int *)p2));
    printf("%p\n", p2);                   //printf("%p\n", p2+5);
    printf("%p\n", (unsigned int *)p2+1); //p2+1*sizeof(unsigned int)
    
    //(unsigned char *)p2 把p2从viod *临时强制类型转换为unsigned char *(欺骗计算机)
    //此时(unsigned char*)p2+1==  (unsigned char *)p2+1*sizeof(unsigned char)
    
    printf("%p\n", (unsigned char *)p2+1);
    
    //(unsigned short *)p2 把p2从viod *临时强制类型转换为unsigned short *(欺骗计算机)
    //此时(unsigned short*)p2+1==  (unsigned short *)p2+1*sizeof(unsigned short)
    
    printf("%p\n", (unsigned short *)p2+1);
    
    //(unsigned int)p2 -->把把p2从viod *临时强制类型转换为unsigned int,
    //此时(unsigned int)p2+1==  (unsigned int)p2+1
    //此时(unsigned int)p2+5==  (unsigned int)p2+5
    printf("%p\n", (unsigned int)p2+5); 
    
    return 0;
    
}
​

指针强制类型转化例子:

#include <stdio.h>
#include <strings.h>

int main()
{
    unsigned int a =0x12345678;
    unsigned int *p = &a;
    
    //p1-->的类型为:unsigned char *, &a的类型为:unsigned int *
    
    unsigned char *p1 = &a;
    printf("a:%x\n", a);        //12345678
    printf("*p:%x\n", *p);        //12345678
    printf("*p1:%x\n", *p1);     //78
    return 0;
}

 

⑧. NULL(空指针)

指针的零值:#define NULL (void *)0x0
int *p ;  //野指针,里面的内存地址是不确定,非常危险
int *p = NULL;  //指针变量量定义后,未初始化,最好赋值等于NULL
*p = 100;
​
对NULL指针解引用会爆段错误:
Segmentation fault (core dumped)  -->段错误(非法访问没有访问权限的内存)

4. 二级指针

①. 概念:指针变量用来存储变量内存地址

一级指针存储除了指针变量之外变量的地址

二级指针存储一级指针变量地址

②. 模型:一级指针变量类型 *变量名;

int a=100;
int *p =&a;
int **q=&p;

③. 二级指针的大小:

32位系统占4个字节
64位系统占8个字节
int **q;
sizeof(q) == 4;

④. 二级指针数据类型问题

int a=100;  a的数据类型是:int     
            100的类型是:int  
            &a的类型是:int  *
    
int *p = &a;    p的数据类型是:int *  
                &a的类型是:int  *
                &p的类型是:int  **
​
int **q=&p;    q的数据类型是:int **
               &p的类型是:int  **
               &q的类型是:int  ***

5.数组指针

①. 概念:本质是一级指针,用来存储数组的地址

int a[3]; //数组a的类型是: int ()[3]
          //&a的类型是:int (*)[3]
​
int (*p)[3] = &a; //定义一个数组指针,把数组a的地址存储到数组指针变量p里面
​
int b[4];  //数组b的类型是: int ()[4]
            //&b的类型是:int (*)[4]
            
int (*p1)[4] = &b; //定义一个数组指针,把数组b的地址存储到数组指针变量p1里面
​
int c[2][3]; //数组c的类型是: int ()[2][3]
            //&c的类型是:int (*)[2][3]
            
int (*p2)[2][3] = &c; //定义一个数组指针,把数组c的地址存储到数组指针变量p2里

②. 模型

char a[10];     //它的类型为:char ()[10]
                //&a的类型为:char (*)[10]
                
char (*p)[10] = &a;
​
--------------------
int a[2];   //它的类型是:int ()[2]  不等价的 int ()[10]
            //&a的类型为:int (*)[2]
​
定义一个相应类型的指针变量合法存储数组地址
int (*p)[2] = &a;
int (*p1)[10] = &a; //不合法存储
​
--------------------
int a[2][3];    //它的类型是:int ()[2][3]
                //&a的类型为:int (*)[2][3]
int (*p)[2][3] = &a
​
-------------------
模型:
数组的数据类型 *变量名

③. 内存大小

32位系统占4个字节
64位系统占8个字节

④. 数组指针公式: *(p+1) == p[1] == *(1+p) == 1[p]

                                *(a+1) == a[1] == *(1+a) == 1[a]

例如:
#include <stdio.h>
#include <strings.h>
​
int main()
{
​
    int a[3]={1, 2, 3};
    int *p=&a[0];   //int *p=a;
    
    printf("*(p+1):%d\n", *(p+1));      //*(p+1) == p[1] == *(1+p) == 1[p]
    printf("*(a+1):%d\n", *(a+1));      //*(a+1) == a[1] == *(1+a) == 1[a]
    
    printf("*(1+p):%d\n", *(1+p)); 
    printf("*(1+a):%d\n", *(1+a));      //*(a+1) == a[1]
    
    printf("a[1]:%d\n", a[1]);  //a --> int *
    printf("p[1]:%d\n", p[1]);  //p --> int *
    printf("1[a]:%d\n", 1[a]);  //a --> int *
    printf("1[p]:%d\n", 1[p]);  //p --> int *
    
    //比较特别的地方
    printf("sizeof(a):%d\n", sizeof(a)); //sizeof(a)表示数组a的大小        
    printf("sizeof(p):%d\n", sizeof(p));//sizeof(p)表示指针变量p的大小   
​
    printf("*(p+2):%d\n", *(p+2));  
    printf("*(a+2):%d\n", *(a+2));  
    
    return 0;
}

6.指针数组

①. 概念:本质是一个一维数组,它的元素类型是指针

int a=100;
int b=200;
int c=300;
int d=400;

/*int *p1=&a;
int *p2=&b;
int *p3=&c;
int *p4=&d;*/

定义指针数组
(int *) array[4];  int *array[4];
array[0] = &a; //非初始化赋值
array[1] = &b;
array[2] = &c;
array[3] = &d;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值