数组、指针数组与数组指针

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/maoliran/article/details/51953041

一、数组类型

注意:
(1)数组首元素的地址与数组地址是完全两个不同的概念

int a[10];
printf("a : %d,  a + 1 : %d\n", a, a + 1);
printf("&a : %d,  &a + 1 : %d\n", &a, &a + 1);

输出结果:

这里写图片描述

(2)数组元素的首地址是常量,不能修改,这是为了释放内存空间所必需的,否则找不到释放内存空间的首地址了

(3)定义一个数组类型
定义数组类型的格式如下:

typedef int(ARRAY)[5];

其中ARRAY便是这个数组类型的名字。

举个例子:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(){
    typedef int(ARRAY)[5];
    ARRAY a;    //相当于 int a[5];
    for (int i = 0; i < 5; i++)
        a[i] = i + 1;
    for (int i = 0; i < 5; i++)
        printf("a[%d] : %d\n", i, a[i]);
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

二、指针数组

1、指针数组的定义

int *a[5];

a就是一个指针数组

2、指针数组的应用

(1)菜单

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//获取菜单中标题的位置下标
int getpos(char** mymenu, const char* key, int* pos) {
    int ret = 0;
    if (mymenu == NULL || key == NULL || pos == NULL) {
        ret = 1;
        printf("func getpos mymenu == NULL || key == NULL || pos == NULL err : %d\n", ret);
        return ret;
    }
    *pos = 0;
    for (int i = 0; mymenu[i] != NULL; i++) {
        if (strcmp(key, mymenu[i]) == 0) {
            *pos = i;
            return ret;
        }
    }
    return ret;
}


int main() {
    int pos = 0;
    char* mymenu[] = { "while", "for", "do", "switch", "case", 0 };
    char key[64] = "do";
    getpos(mymenu, key, &pos);
    printf("pos : %d\n", pos);
    for (int i = 0; mymenu[i] != NULL; i++) {
        printf("%s\n", mymenu[i]);
    }
    system("pause");
    return 0;
}

输出结果:
这里写图片描述

mymenu是个指针数组,传给行参时,可以是char** mymenu,也可以是char* mymenu[],指针数组传参时会退化成指针,这是C语言的强大,不需要知道这个数组里面究竟放了几个元素,可以根据最后一个元素为空,这就需要用到指针数组的自我结束能力,或者传给一个数组大小的参数。

这里牵扯到指针数组的自我结束能力,也就是说程序员在定义指针数组的元素时,把最后一个设为空,那么编译器就能知道到这里就结束了。

比如:

char* mymenu1[] = { "while", "for", "do", "switch", "case", '\0' };
char* mymenu2[] = { "while", "for", "do", "switch", "case", 0 };
char* mymenu3[] = { "while", "for", "do", "switch", "case", NULL };

这里的三种结束方式都是可以的。

(2)命令行

int main(int argc, char* argv[], char** env) {
    printf("\n-----------------begin argv-------------------\n");
    for (int i = 1; i < argc; i++) {
        printf("%s\n", argv[i]);
    }
    printf("\n-----------------end argv-------------------\n");
    printf("\n-----------------begin env-------------------\n");
    for (int i = 0; env[i] != NULL; i++) {
        printf("%s\n", env[i]);
    }
    printf("\n-----------------end env-------------------\n");
    system("pause");
    return 0;
}

输出结果(这里是用cmd执行的):
这里写图片描述

可以看到main函数的参数argv和env实际都是二级指针,argv写成了指针数组的形式而已。

再扩展一下main函数的内存分配,都知道main函数是程序的入口,那么exe程序跑起来,也就是操作系统调用了main函数,那么就有操作系统为main函数分配内存空间,调起来之后再把内存空间的首地址扔给main函数,让main函数继续执行内存的分配释放等各种操作。比如上面菜单的那个例子main函数调用了getpos函数,则由main函数为getpos分配内存空间,也就是说谁调用的谁就去分配内存空间。

所以说在企业的项目开发过程中,不管是使用的MFC框架,QT框架,还是linux内核,程序员只是使用各种api,往里面填参数而已,实际都是框架里把内存分配好了。

三、数组指针

1、数组指针的定义方式

(1)数组类型定义

typedef int(arrayType) [5];
int a[3][5];
arrayType* myarray = &a;

(2)数组指针类型

typedef int(*pArrayType) [5];
int a[3][5];
pArrayType pArray = &a;

(3)直接定义

int a[3][5];
int (*pArray)[5] = a;

2、多维数组的本质

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


int print_array(int* array, int n, int m) {
    int ret = 0;
    if (array == NULL) {
        ret = 1;
        printf("func print_array err : %d\n", ret);
        return ret;
    }
    for (int i = 0; i < n * m; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    return ret;
}

int main(){
    int a[3][5];
    printf("a : %d,  a + 1 : %d\n", a, a + 1);
    printf("&a : %d,  &a + 1 : %d\n", &a, &a + 1);
    int(*pArray)[5] = a;
    int temp = 1;
    printf("pArray : %d, pArray + 1 : %d\n", pArray, pArray + 1);
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            *(*(pArray + i) + j) = temp++;
        }
    }
    print_array((int*)a, 3, 5);
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

可以看到a是二维数组的首元素地址,a + 1跳了一个一位数组的距离,也就是5 * 4 = 20个单位,跟数组指针加1跳的步长是一样的。&a是整个二维数组的首地址,&a + 1跳了5 * 4 * 3 = 60个单位。

二维数组赋给数组指针后,可以通过数组指针改变二维数组的值,先看以前写的一位数组转指针的过程:

a[i] ===》  a[0 + i] ===》  *(a + i)

那么二维数组转数组指针是一个道理

a[i][j] ===》 a[0 + i][j] ===》 *(a + i)[j]  ===》  *(a + i)[0 + j]  ===》  *(*(a + i) + j)

3、多维数组在内存中的存储

虽然是多维数组,但实际多维数组在内存中还是按照线性存储的,从上面的代码中看出,在print_array函数中的第一个形参是一级指针,利用这个一级指针仍然把二维数组的值给打印出来了。

展开阅读全文

没有更多推荐了,返回首页