C语言复习: 二级指针和多级指针

二级指针内存模型建立

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);

    }

}

C语言复习: 二级指针和多级指针

数组类型和多维数组本质

数组概念

概念

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

C语言复习: 二级指针和多级指针

数组初始化

 

 

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]

    */

}

 

C语言复习: 二级指针和多级指针

结论: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");

}

上一篇:VMWare 安装 Linux


下一篇:BestCoder Round #89 B题---Fxx and game(单调队列)