二级指针内存模型建立

void main2()

{

    int i = 0;

 

    //指针数组

    char * p1[] = { "123", "456", "789" };//二级指针的第一种内存模型

 

                                            //二维数组

    char p2[3][4] = { "123", "456", "789" };//二级指针的第二种内存模型

 

    //手工二维内存: 二级指针的第三种内存模型

    char **p3 = (char **)malloc(3 * sizeof(char *)); //int array[3];

    for (i = 0; i<3; i++)

    {

        p3[i] = (char *)malloc(10 * sizeof(char)); //char buf[10]

 

        sprintf(p3[i], "%d%d%d", i, i, i);

    }

}

数组类型和多维数组本质

数组概念

概念

  • 1)元素类型角度:数组是相同类型的变量的有序集合
  • 2)内存角度:联系的一大片内存空间

数组初始化

 

 

int main()

{

    int i = 0;

    int a[10] = { 1,2 }; //其他初始化为0

    int b[] = { 1, 2 };

    int c[20] = { 0 };

 

    for (i = 0; i<10; i++)

    {

        printf("%d ", a[i]);

    }

    memset(a, 0, sizeof(a));

    getchar();

    return 0;

数组名的技术盲点

  • 1)数组首元素的地址和数组地址是两个不同的概念
  • 2)数组名代表数组首元素的地址,它是个常量。
    • 解释如下:变量本质是内存空间的别名,一定义数组,就分配内存,内存就固定了。所以数组名起名以后就不能被修改了。
  • 3)数组首元素的地址和数组的地址值相等
  • 4、怎么样得到整个一维数组的地址?

C语言规定:

int a[10];

printf("得到整个数组的地址a: %d \n", &a);

printf("数组的首元素的地址a: %d \n", a);

//虽然值是一样的,但是代表的意思是不一样的.

怎么样表达int a[10]这种数据类型? 为int[10]类型.

数组类型、数组指针类型、数组指针类型变量

数组类型

  • 1数据类型分为基础、非基础,思考角度应该发生变化
  • 2 C语言中的数组有自己特定的类型
    • 数组的类型由元素类型和数组大小共同决定
    • 例:int array[5]的类型为int[5]
  • 3定义 数组类型,并用数组类型定义变量

int main()

{

    typedef
int(MYINT5)[5];

    int i = 0;

    MYINT5 array;

    for (i = 0; i<5; i++)

    {

        array[i] = i;

    }

 

    for (i = 0; i<5; i++)

    {

        printf("%d ", array[i]);

    }

 

    getchar();

    return 0;

}

 

数组指针类型

  • 数组指针用于指向一个数组

int a[10]

数组名是数组首元素的起始地址,但并不是数组的起始地址

通过将取地址符&作用于数组名可以得到整个数组的起始地址

//定义数组指针 有两种

1)通过数组类型定义数组指针:

typedef
int(ArrayType)[5];

int *a;

ArrayType* pointer;

2) 声明一个数组指针类型

typedef int(*MyPointer)[5];

MyPointer myPoint;

3)直接定义:

int (*pointer)[n];

    pointer    为数组指针变量名

    type    为指向的数组的类型

    n        为指向的数组的大小

注意这个地方是type类型(比如 int (*pointer)[10])

 

  • 数组指针:用数组类型加*定义一个数组指针

int mian()

{

    int a[5];

    //声明一个数组类型

    typedef
int(MYINT5)[5];

    //用数组类型 加*,定义一个数组指针变量

    MYINT5 *array;

    array = &a;

    for (i = 0; i<5; i++)

    {

        (*array)[i] = i;

    }

    //

    for (i = 0; i<5; i++)

    {

        printf("\n%d %d", a[i], (*array)[i]);

    }

}

 

    数组指针:定义一个数组指针类型,然后用类型定义变量

int b[5];

//声明一个数组指针类型

typedef
int(*MyPointer)[5];

//用数组指针类型,去定义一个变量

MyPointer mypoint;

mypoint = &b;

for (i = 0; i<5; i++)

{

    (*mypoint)[i] = i;

}

//

for (i = 0; i<5; i++)

{

    printf("\n%d %d", b[i], (*mypoint)[i]);

}

    }

 

    //3数组指针:直接定义一个数组指针变量

    

{

int c[5];

//直接声明一个数组指针变量

int(*pointer)[5] = &c;

for (i = 0; i<5; i++)

{

    (*pointer)[i] = i;

}

for (i = 0; i<5; i++)

{

    printf("\n%d %d", c[i], (*pointer)[i]);

}

}

多维数组本质技术推演

//int a[10];

//char myarray[3][5] PK int(*p)[5]

//myarray名称到底是什么?

//多维数组char a[i][j] == > *(*(a + i) + j)转换技巧分析

void main()

{

    int a[3][5];

 

    int c[5]; //&c + 1;

    int b[10]; //b代表数组首元素的地址 &b代表这个数组的地址 &b+1相当于 指针后移4*10个单位

 

             //a代表什么什么那?a是一个数组指针 指向低维数组的指针

             //a +1; → 跳5*4(int)个字节的内存

    printf("a:%d, a+1:%d \n", a, a + 1); //4*5

 

    {

        int i = 0, j = 0, tmp = 0;

        for (i = 0; i<3; i++)

        {

            for (j = 0; j<5; j++)

            {

                a[i][j] = ++tmp;

            }

        }

 

        printf("\n");

        for (i = 0; i<3; i++)

        {

            for (j = 0; j<5; j++)

            {

                printf("%d \n", a[i][j]);

            }

        }

    }

 

    //a的本质是一个数组指针,每次往后跳一维的维数

    {

        int i = 0, j = 0;

        //定义了一个数组指针 变量

        int(*myArrayPoint)[5]; //告诉编译给我开辟五个四字节内存

        myArrayPoint = a;

        printf("\n");

        for (i = 0; i<3; i++)

        {

            for (j = 0; j<5; j++)

            {

                //myArrayPoint[i][j] = ++tmp;

                printf("%d \n", myArrayPoint[i][j]);

            }

        }

    }

 

    /*

    char cbuf[30]; // cbuf(1级指针) 代表数组首元素的地址 &cbuf(二级指针) 代表整个数组的地址

    char array[10][30]; //array是二级指针

    (array+i) //相当于 整个第i行的数组地址 //二级指针 &cbuf

 

    (*(array+i))//一维数组的首地址 cbuf

 

    (*(array+i))+j //相当于第i行第j列的地址 &array[i][j]

 

    *((*(array+i))+j) //相当于第i行第j列的元素 <====> array[i][j]

    */

}

 

结论:a是一个指向int myarray[5]的数组指针 a+1 向后跳5*4,跳一行。

多维数组做函数参数退化原因大剖析

//证明一下多维数组的线性存储

//线性打印

 

void printfArray411(int *array, int
num)

{

    int i = 0;

    for (i = 0; i<num; i++)

    {

        printf("%d ", array[i]);

    }

}

 

void printfArray412(int(*array)[5], int
num)

{

    return;

}

 

void printfArrr333(int
c[3][4][5])

{

    return;

}

void main()

{

    int a[3][5];

    int c[3][4][5];

    int i, j = 0;

    int tmp = 0;

    for (i = 0; i<3; i++)

    {

        for (j = 0; j<5; j++)

        {

            a[i][j] = tmp++;

        }

    }

 

 

    printfArray411((int *)a, 15);

 

    system("pause");

}

 

多维数组做函数参数技术推演

  1. C语言中只会以机械式的值拷贝的方式传递参数(实参把值传给形参)

int fun(char a[20], size_t b){

   printf("%d\t%d",b,sizeof(a));

原因1:高效

原因2:C语言处理a[n]的时候,它没有办法知道n是几,它只知道&n[0]是多少,它的值作为参数传递进去了;虽然c语言可以做到直接int fun(char a[20]),然后函数能得到20这个数字,但是,C没有这么做。

2、二维数组参数同样存在退化的问题

二维数组可以看做是一维数组

二维数组中的每个元素是一维数组

二维数组参数中第一维的参数可以省略

void f(int a[5]) ====》void f(int a[]); ===》 void f(int* a);

void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]);

3、等价关系

    

数组参数                    等效的指针参数

    

一维数组 char a[30]                指针 char*

指针数组 char *a[30]                指针的指针 char **a

二维数组 char a[10][30]            数组的指针 char(*a)[30]

 

指针数组的应用场景

指针数组的两种用法(菜单 命令行(argv*[]))

    操作系统拉起应用 在框架下干活

    字符数组自我结束标志

    // NULL 0 '\0'

实际上NULL==0=='\0'=0

强化训练

int sort(char *p[], int count, char **p, int *ncount);

int sort(char *p[], int count, char (*p)[30], int *ncount);

int sort(char (*p)[30], int ncount, char **p, int *ncount);

 

//把第一种内存模型和第二种内存模型的结果copy到第三种内存模型中,并排序,打印

char ** sort(char **p1, int num1, char (*p)[30], int num2, int *num3 );

int getArray3_Free(char **p3, int
p3num)

{

    int i;

    if (p3 == NULL)

    {

        return -1;

    }

    for (i = 0; i<p3num; i++)

    {

        if (p3[i] != NULL)

        {

            free(p3[i]);

        }

    }

    free(p3);

}

 

 

int getArray3_Free2(char ***p3, int
p3num)

{

    int i;

    char **tmp = NULL;

 

    if (p3 == NULL)

    {

        return -1;

    }

    tmp = *p3;

 

    for (i = 0; i<p3num; i++)

    {

        if (tmp[i] != NULL)

        {

            free(tmp[i]);

        }

    }

    free(tmp);

 

    *p3 = NULL; //通过间接赋值,去间接的修改实参的值,成0

}

 

int getArray3_2(char **myp1, int
num1, char(*myp2)[30], int
num2, char *** myp3, int *num3)

{

    int ret = 0;

    int i, j;

    int tmpNum3 = 0;

 

    char **tmpp3 = NULL;

    char *temp;

 

    /*

    printf("111111111");

    if (*myp3 ==NULL )

    {

    printf("222222222");

    } */

    printf("33333");

    if (myp1 == NULL || myp2 == NULL || num3 == NULL || myp3 == NULL)

    {

        ret = -1;

        return ret;

    }

    //准备内存

    tmpNum3 = num1 + num2;

    //分配第一维

    tmpp3 = (char **)malloc(tmpNum3 * sizeof(char *));

    if (tmpp3 == NULL)

    {

        return NULL;

    }

 

    //分配第二维 把第一种内存模型数据和第二种内存模型数据,copy到第3中内存模型中

    for (i = 0; i<num1; i++)

    {

        tmpp3[i] = (char *)malloc(strlen(myp1[i]) + 1);

        if (tmpp3[i] == NULL)

        {

            puts("out of space");

            return NULL;

        }

        strcpy(tmpp3[i], myp1[i]);

    }

    for (j = 0; j<num2; j++, i++)

    {

        tmpp3[i] = (char *)malloc(strlen(myp2[j]) + 1); //note modify

        if (tmpp3[i] == NULL)

        {

            puts("out of space");

            return NULL;

        }

        strcpy(tmpp3[i], myp2[j]);

    }

 

    //排序

    for (i = 0; i<tmpNum3; i++)

    {

        for (j = i + 1; j<tmpNum3; j++)

        {

            if (strcmp(tmpp3[i], tmpp3[j])>0)

            {

                temp = tmpp3[i];

                tmpp3[i] = tmpp3[j];

                tmpp3[j] = temp;

            }

        }

    }

 

    //通过间接赋值,把结果甩给实参

    *num3 = tmpNum3;

    *myp3 = tmpp3; //*0 = 100;

    return ret;

}

 

char **getArray3(char **myp1, int
num1, char(*myp2)[30], int
num2, int *num3)

{

    int i, j;

    int tmpNum3 = 0;

 

    char **tmpp3 = NULL;

    char *temp;

 

    if (myp1 == NULL || myp2 == NULL || num3 == NULL)

    {

        return NULL;

    }

    //准备内存

    tmpNum3 = num1 + num2;

    //分配第一维

    tmpp3 = (char **)malloc(tmpNum3 * sizeof(char *));

    if (tmpp3 == NULL)

    {

        return NULL;

    }

 

    //分配第二维 把第一种内存模型数据和第二种内存模型数据,copy到第3中内存模型中

    for (i = 0; i<num1; i++)

    {

        tmpp3[i] = (char *)malloc(strlen(myp1[i]) + 1);

        if (tmpp3[i] == NULL)

        {

            puts("out of space");

            return NULL;

        }

        strcpy(tmpp3[i], myp1[i]);

    }

    for (j = 0; j<num2; j++, i++)

    {

        tmpp3[i] = (char *)malloc(strlen(myp2[j]) + 1); //note

        if (tmpp3[i] == NULL)

        {

            puts("out of space");

            return NULL;

        }

        strcpy(tmpp3[i], myp2[j]);

    }

 

    //排序

    for (i = 0; i<tmpNum3; i++)

    {

        for (j = i + 1; j<tmpNum3; j++)

        {

            if (strcmp(tmpp3[i], tmpp3[j])>0)

            {

                temp = tmpp3[i];

                tmpp3[i] = tmpp3[j];

                tmpp3[j] = temp;

            }

        }

    }

 

    *num3 = tmpNum3;

    return tmpp3;

}

 

void main()

{

    int num3 = 0, i = 0;

    int ret = 0;

    char *p1[] = { "222222", "1111111", "33333333" };

    char p2[4][30] = { "bbbbb", "aaaaa", "zzzzzz", "ccccccc" };

    char **p3 = NULL;

    char ***myerrp3 = NULL;

 

    //p3 = getArray3(p1, 3, p2, 4, &num3);

    //ret = getArray3_2(p1,3, p2, 4, &p3, &num3);

    ret = getArray3_2(p1, 3, p2, 4, 0, &num3); //错误做法

    if (ret != 0)

    {

        return;

    }

    for (i = 0; i<num3; i++)

    {

        printf("%s \n", p3[i]);

    }

 

    //getArray3_Free(p3, num3);

    //    p3=NULL;

    getArray3_Free2(&p3, num3);

 

    printf("p3:%d \n", p3);

 

    system("pause");

}

C语言复习: 二级指针和多级指针的更多相关文章

  1. [转] C语言多维数组与多级指针

    http://c.biancheng.net/cpp/html/477.html 多维数组与多级指针也是初学者感觉迷糊的一个地方.超过二维的数组和超过二级的指针其实并不多用.如果能弄明白二维数组与二级 ...

  2. 嵌入式C语言4.4 C语言内存空间的使用-多级指针

    多级指针 int **p; 存访地址的地址空间

  3. [C++]指针与多级指针(图解)

    声明:如需引用或者摘抄本博文源码或者其文章的,请在显著处注明,来源于本博文/作者,以示尊重劳动成果,助力开源精神.也欢迎大家一起探讨,交流,以共同进步- 0.0 演示: /* @author:John ...

  4. C语言复习:字符串和一级指针

    字符串基本操作 字符数组初始化方法 int main() {     //1 {}号法 初始化列表     //数组初始化有2种方法 默认元素个数.指定元素个数     char buf1[] = { ...

  5. C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数

    1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...

  6. C语言复习---二维数组和二级指针的关系:没关系,别瞎想(重点)

    前提:一维数组和一维指针为什么可以替换使用? ] = { , , }; int *p = a; ; i < ; i++) printf("%d ", *(p + i)); 上 ...

  7. Android For JNI(五)——C语言多级指针,结构体,联合体,枚举,自定义类型

    Android For JNI(五)--C语言多级指针,结构体,联合体,枚举,自定义类型 我们的C已经渐渐的步入正轨了,基础过去之后,就是我们的NDK和JNI实战了 一.多级指针 指针的概念我们在前面 ...

  8. Android JNI编程(四)——C语言多级指针、数组取值、从控制台输入数组

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一:前面我们介绍了一级指针的相关概念和用发,今天我们就来说一说多级指针. 1 ...

  9. C语言 详解多级指针与指针类型的关系

    //V推论①:指针变量的步长只与‘指针变量的值’的类型有关(指针的值的类型 == 指针指向数据的类型) //指针类型跟指针的值有关,指针是占据4个字节大小的内存空间,但是指针的类型却是各不相同的 // ...

随机推荐

  1. Jmeter(二十八)Jmeter-Question之“HTTPS请求”

    前面在Jmeter-Question中有提到若干问题,有时间呢,我也会进行继续编写随笔,梳理自己的知识,本篇呢,便来记Jmeter发送https请求的过程 内容大致与http://blog.csdn. ...

  2. [UE4]蓝图调试

    1.蓝图下断点:选择蓝图节点按F9下断点:再按一下F9就会去掉断点. 2.游戏运行到断点会自动这暂停,鼠标移到某个变量上面,会显示该变量的值. 3.按F10执行下一步. 4.蓝图调试没有跳出函数的功能 ...

  3. Linux双网卡绑定

    Linux双网卡绑定 作者:Eric 微信:loveoracle11g eth0和eth1绑定为bond0 [root@rac-node1 ~]# cat /etc/sysconfig/network ...

  4. 1449 - The user specified as a definer ('test'@'%') does not exist

    最近在做一个项目,由于服务器切换,所以需要将原有服务器的mysql数据表以及存储过程导入到另一个服务器的mysql数据库中.导入完成之后以为一切是那么的简单,却没有想到总还是出现了一些莫名其妙的问题. ...

  5. 网络基础和python

    ·五层协议 物理层,数据链路层,网络层,传输层,应用层 ·用户上网流程 1.本机获取 2.打开浏览器,,输入网址. 3.dns协议(基于udp协议) 4.HTTP部分的内容 5 TCP协议 6 IP协 ...

  6. python利用socket写一个文件上传

    1.先将一张图片拖入‘文件上传’的目录下,利用socket把这张图片写到叫‘yuan’的文件中 2.代码: #模拟服务端 import subprocess import os import sock ...

  7. 背景图片的移动----background-attach-----background-repeat

    background-repeat:默认是平铺的,也即是还有空间的话将一张接着一张显示 设置为 no-repeat  就最多显示一张 background-attachment:设置是否固定图片,在有 ...

  8. [Unity工具]嵌套Prefab

    在父Prefab中嵌套子Prefab,那么如果对这个嵌套Prefab进行修改,改变将不会应用到子Prefab中:同理,对子Prefab的修改,也不会应用到这个嵌套Prefab中.因此,就会出现一些问题 ...

  9. 改变jupyter notebook默认初始文件路径 - 关于快捷方式

    jupyter notebook home path changing - %USERFROFILE% and Configure file 如何改变jupyter notebook默认初始文件路径, ...

  10. 25.安装配置phantomjs

    1.官网下载windows版本:http://phantomjs.org/download.html2.下载完解压,将PhantomJS可执行文件配置到环境变量里.比如: 将 E:\Soft\soft ...