深入理解C指针 指针和多维数组的关系

1.数组名是什么

  数组名是一个标识符,它标识出我们之前申请的一连串内存空间,而且这个空间内的元素类型是相同的——即数组名代表的是一个内存块及这个内存块中的元素类型 数组名的值是数组首元素的指针常量。
  数组名不是指针,但大多数使用到数组名的地方,编译器都会把数组名隐式转换成一个指向数组首元素的指针来处理。只有两种情况下例外:

  int a[ ] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  1)第一种是对数组名使用sizeof运算符:

sizeof(a)

这将会得到整个数组所占的内存大小,a是长度为10的int(4字节)数组,运算结果是40

  2) 第二种是对数组名取地址:  &a

运算结果是数组的地址。注意,数组的地址和数组首元素的地址是不同的概念,尽管二者的值是相同的。

2.下标引用

    一维数组int arr[i] 可以表示为 *(arr + i)  arr的值被转换成指针常量,指向第一个元素,向右移动i * sizeof(int)个字节,然后解引用,便得到了第i个元素的内容。因为第一种写法会自动转换成第二种,这个过程需要一些开销,所以我们说第二种写法通常效率会高一些。

3.数组的类型

以一维数组 int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };为例:

  数组a的类型是 int *    a 是指向元素的指针。数组的类型取决于数组元素的类型:如果它们是int类型,那么数组名的类型就是“指向int的常量指针”;如果它们是其他类型,那么数组名的类型就是“指向其他类型的常量指针”。(出自《C和指针》第141页)

  &a 的类型是 int (*)[10]   &a是指向数组的指针。  取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量值的指针(出自《C和指针》第142页)。

    int a[5] = { 1,2,3,4,5 };
    printf("%p
%p", a, &a);

    printf("
%d %d %d", sizeof(a), sizeof(*a), sizeof(*&a)); //20 4 20
    printf("
%p
%p", a, &a + 1);

    int *p = a;
    int(*pInt)[5] = &a;
    printf("
%d,%d", sizeof(*p), sizeof(*pInt)); //4 20

二维数组

  二维数组的类型同样取决于数组元素的类型,假设有二维数组int b[2][5]

因为C语言的多维数组实际上是一维数组,二维数组实际上只是一个一维数组,只不过里面每个元素又是一个一维数组而已。

  所以b的类型是int (*)[5],而&b的类型是int (*)[2][5]

    int a[2][5] = { 1,2,3,4,5,6,7,8,9,0 };
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            printf("%d,%p  ", a[i][j], &a[i][j]);
        }
        putchar('
');
    }
    printf("
%d   %d   %d   %d
", sizeof(a),sizeof(*a),sizeof(**a),sizeof(*&a));
    printf("%p
", a);
    printf("%p
", a + 1);

    printf("%p
", *a);
    printf("%p
", *a + 1);
    printf("%p
", *(a + 1));

    printf("%p
", &a);
    printf("%p
", &a + 1);

 

  sizeof(a)会得到整个数组所占内存大小。sizeof(*a)会得到一行数组所占内存大小。sizeof(**a)会得到一个元素所占内存大小。

  *a是首元素的地址,*a + 1是指向下一个元素的地址,*(a + 1)指向下一行的地址。

  a是行指针,指向一个共有5个元素的一维数组地址,a + 1地址增加20字节,下一行地址:%p 转换10进制加上 20字节,再转换16进制。

  &a是一个指向二维数组指针,10个元素40字节,&a + 1地址增加40字节,相当于指向了下一个数组(实际上并不存在),或者说指向了数组a最后一个元素的下一个元素,这在C++里称为尾后指针。

 

  由于 a[i] = *(a + i) 那么一个二维数组int a[i][j]。

    那么a[i]+j 表示i行j列元素的地址,所以 *(a[i] + j)表示a[i][j]的元素。

  既然 *(*(a + i) + j)与* (a[i] + j)等价,表示a[i][j]的元素。

二级指针与指针数组的关系:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <ctype.h>
void main()
{
    char * cmd[] = { "notepad","calc","mspaint","write" }; //指针数组 数组的每一个元素都是一个指针 
    for (char **p = cmd; p < cmd + 4; p++)//指针循环方式循环指针数组
    {
        printf("%p", p);        
        printf("   %s", *p);//*p是一个指针变量,存储一个常量字符串的首地址   
        printf("   %c
", **p); //**p等价于*str[0]等价于‘n’
    }

    char *arry[] = { "Hello","world","Pumpkin","Comparative" }; //存储char *类型地址的数组 - 指针数组
    printf("%s
", arry[0]);//Hello arry[0]是一个地址
    printf("%c
", *(arry[0]));//H
    printf("%c
", *(arry[2] + 4));//k
    system("pause");
}

指针做输入第一种模型:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void printMyArray(char *myArray[5], int num)
{
    for (int i = 0; i < num; i++)
        printf("%s
", myArray[i]);//*(myArray + i)
}
void sort(char ** myArray, int num)
{
    char *temp = NULL;
    int i = 0;
    int j = 0;

    for (i = 0; i < num - 1; i++)
        for (j = i + 1; j < num; j++)
        {
            if (strcmp(myArray[i], myArray[j]) > 0)//if(myArray[i] > myArray[j]) 即是错误
            {
                temp = myArray[i];
                myArray[i] = myArray[j]; //交换指针值 改变指针指向
                myArray[j] = temp;
            }
        }
}
int main(void)
{                        //存储char *类型地址的数组 -指针数组
    char *myArray[5] = { "Hello","world","Pumpkin","Comparative","Baby" };

    int num = sizeof(myArray) / sizeof(myArray[0]);
    puts("--------排序之前--------:");
    printMyArray(myArray, num);

    puts("--------排序之后--------:");
    sort(myArray, num);
    printMyArray(myArray, num);
    system("pause");
}

指针做输入第二种模型:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
    //void printMyArray_error(char **myArray, int num)
    // 不能用这种         char ** 与char[5][30]    的间接级别不同
    //指针布长不一样 指针所指数据内存空间的数据类型不一样
void printMyArray(char myArray[][30], int num)
{
    for (int i = 0; i < num; i++)
        printf("%s
", *(myArray + i));
}
void sortMyArray2(char (*myArray)[30], int num)
{
    char tempBuf[30];
    for (int i = 0; i < num - 1; i++)
        for (int j = i; j < num; j++)
            if (strcmp(myArray[i], myArray[j]) > 0)
            {
                strcpy(tempBuf, myArray[i]);//交换内存块
                strcpy(myArray[i], myArray[j]);
                strcpy(myArray[j], tempBuf);
            }
}
int main(void)
{
    char myArray[5][30] = { "Hello","world","Pumpkin","Comparative","Baby" };
    int num = sizeof(myArray) / sizeof(myArray[0]);

    puts("--------排序之前--------:");
    printMyArray(myArray, num);

    sortMyArray2(myArray, num);
    puts("--------排序之后--------:");
    printMyArray(myArray, num);

    system("pause");
}
原文地址:https://www.cnblogs.com/Yang-Xin-Yi/p/13543841.html