【C语言敲重点(一)】二维数组、指针和函数的“恩怨情仇“


一、二维数组的理解

(1)二维数组array[i]和array[i] [j]的理解

  • 二维数组:本质上是以数组作为数组元素的数组,即"数组的数组"。也称为矩阵,行、列数相等时称为方阵。
  • array[i]:表示二维数组第 i 行的一维数组的地址(地址、地址、地址)。
  • array[i] [j]:表示二维数组第 i 行第 j 列元素的值。
#include <stdio.h>
int main() {
    
    
    int array[3][4] = {
    
    
            {
    
    1,2,3,4},
            {
    
    5,6,7,8},
            {
    
    9,10,11,12},
    };
    /* 1.array[i]是每一行的数组(一维)的地址 */
    int i,j;
    for(i=0;i<3;i++){
    
    
        printf("%p\n",array[i]);
    }
    /* 2.array[i][j]是每一行数组(一维)的值 */
    for(i=0;i<3;i++){
    
    
        for(j=0;j<4;j++){
    
    
            printf("%d  ",array[i][j]);
        }
        putchar('\n');
    }
    return 0;
}

在这里插入图片描述

(2)array[i]+j、*array[i]+j的理解

  • array[i]+j:二维数组第 i 行第 j 列的地址

  • *array[i]+j:二维数组第 i 行第 j 列的地址的值

    注意:*array[i]+j和*(array[i]+j)写法不同,表示意思相同

#include <stdio.h>
int main() {
    
    
    int array[3][4] = {
    
    
            {
    
    1,2,3,4},
            {
    
    5,6,7,8},
            {
    
    9,10,11,12},
    };
    /* 1.array[i]+j:二维数组的i行第j列的地址 */
    /* 2.*array[i]+j:二维数组第i行第j列的地址的值(元素的值) */
    /* PS:*array[i]+j和*(array[i]+j)意思一样(*和+运算符优先级一样,遵循从右往左计算) */
    int i,j;
    for(i=0;i<3;i++){
    
    
        for(j=0;j<4;j++){
    
    
            printf("%d\t",*array[i]+j);
        }
        putchar('\n');
    }
    return 0;
}

在这里插入图片描述

(3)二维数组名array的理解

在前面一维数组的认知中,我们知道数组名就是数组的首地址,可以通过数组首地址来操作数组元素。同样地,在二维数组中,二维数组名array也表示二维数组的首地址,只是该地址存放的是每一组一维数组的首地址。也就是说,二维数组名是一个存放其一维数组首地址的地址("地址的地址")。所以array[i]也可以写成*(array+i);array[i]+j可以写成(*(array+i))+j;可以理解成以array为基地址,*(array+i)偏移i得到第i行的首地址,(*(array+i))+j再偏移j得到第i行第j列元素的地址;或许有亿点点绕,亿点点晕,继续体会下面的代码吧

  • array:二维数组名,是存放其一维数组首地址的地址(二维数组名虽然在理解上有点类似二级指针,但是二维数组名并不同于二级指针)
#include <stdio.h>
int main() {
    
    
    int array[3][4] = {
    
    
            {
    
    1,2,3,4},
            {
    
    5,6,7,8},
            {
    
    9,10,11,12},
    };
    int i,j;
    for(i=0;i<3;i++){
    
    
        for(j=0;j<4;j++){
    
    
           printf("%d\t",*array[i]+j);	//写法一
           printf("%d\t",*(*(array+i))+j);	//写法二(输出结果可以看到,两种写法等价)
        }
        putchar('\n');
    }
    return 0;
}

在这里插入图片描述

二、指针的各种"形态"

(1)数组指针

  • 数组指针:指向数组的指针,也就是指向数组首地址的地址。(其实和上面所说的array差不多)

  • int (*p)[4] = array(array是二维数组名):定义一个指向有4个元素的二维数组首地址的指针变量。

    (二维数组实质上同一维数组一样,在内存中的地址空间连续,可以通过指针进行操作)

  • 根据用户输入的行、列值输出二维数组中的指定行列元素,要求使用数组指针实现。

#include <stdio.h>

void getInput(int *i,int *j){
    
    
    printf("请输入行、列值(从1开始):");
    scanf_s("%d %d",i,j);
    printf("input done\n");
}

int findTargetValue(int (*p)[4],int i,int j){
    
    
    int targetValue;
//    targetValue = p[i][j];
    targetValue = *(*(p+i))+j;
    return targetValue;
}

int main() {
    
    
    int array[3][4] = {
    
    
            {
    
    1,2,3,4},
            {
    
    5,6,7,8},
            {
    
    9,10,11,12},
    };
    int i,j;
    int targetValue;
    getInput(&i,&j);
    targetValue = findTargetValue(array,i-1,j-1);
    printf("矩阵%d行%d列的数据是:%d",i,j,targetValue);
    return 0;
}

在这里插入图片描述

(2)函数指针

【2-1】函数指针的理解
  • 函数指针:指向函数的指针,存放函数的地址的指针变量。
  • 定义:int (*p)(const char *format, …);
  • 赋值(初始化,使其指向某个函数—函数名也是地址):p = printf;
  • 调用:(*p)(“Hello World”);
#include <stdio.h>
int main() {
    
    
    int (*p)(const char *format, ...) =  printf;
    (*p)("Hello World\n");
    return 0;
}

在这里插入图片描述

【2-2】函数指针的应用
  • 应用:根据程序运行过程中的不同情况,调用不同的函数(类似于Java中的接口)+
  • 例:有两个整数a和b,由用户输入1,2或3,如输入1程序给出a和b中大者,输入2就给出a和b中小者,输入3则求a和b的和。
#include <stdio.h>
#include <stdlib.h>

int getMax(int data1,int data2){
    
    
    return data1>data2 ? data1:data2;
}
int getMin(int data1,int data2){
    
    
    return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2){
    
    
    return (data1+data2);
}

int getCommandAndHandle(int data1,int data2,int (*p)(int, int)){
    
    
    int choise = 0;
    printf("请输入1-取大值、2-取小值、3-求和:\n");
    scanf_s("%d",&choise);
    switch (choise) {
    
    
        case 1:
            p = getMax;
            break;
        case 2:
            p = getMin;
            break;
        case 3:
            p = getSum;
            break;
        default:
            printf("error\n");
            exit(-1);
    }
    return (*p)(data2,data1);
}

int main() {
    
    
    int data1 = 10;
    int data2 = 20;
    int result;
    int (*command)(int, int) = NULL;
    result = getCommandAndHandle(data1,data2,command);
    printf("%d\n",result);
    return 0;
}

  • Linux创建线程函数:int pthread_create(pthread_t *th, const pthread_attr_t *attr, void ( func)(void *), void *arg);

    和C++ QT的信号与槽的回调函数底层逻辑——函数指针实现。

三、数组、指针和函数的"傻傻分不清楚"

在这里插入图片描述在这里插入图片描述

(1)指针数组

  • 指针数组:数组元素全为指针类型变量的数组称为指针数组(①是数组;②数组元素是指针)

  • 如何定义:一个有4个整型变量元素的指针数组:int *p[4]

    区别前面的数组指针int (*p)[4],可以知道优先级[]比*高

(2)函数指针数组

  • 函数指针数组:①是数组;②数组元素是指针;③指针指向函数的地址

  • 如何定义:int (*p[4])(int,int)

    优先级:() > [] > *;到了这里,优先级对理解记忆这些东西显得十分关键

  • 例:传入两个数值,分别输出最大值,最小值以及两数的和(函数指针数组)

#include <stdio.h>

int getMax(int data1,int data2){
    
    
    return data1>data2 ? data1:data2;
}
int getMin(int data1,int data2){
    
    
    return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2){
    
    
    return (data1+data2);
}

void getAllResult(int data1,int data2,int (*p[3])(int,int)){
    
    
    printf("Max  Min  Sum\n");
    for(int i=0;i<3;i++){
    
    
        printf("%d   ",(*p[i])(data1,data2));
    }
}

int main() {
    
    
    //函数指针
    //int (*p)(int,int);
    //函数指针数组
    int (*p[3])(int,int) = {
    
    getMax, getMin, getSum};
    getAllResult(88,99,p);
    return 0;
}

在这里插入图片描述

(3)指针函数

  • 指针函数:返回值是指针类型的函数(①是函数;②函数返回值是指针)
  • 定义:int *p(int i,int j)
  • 根据用户指定的行号,输出给定二维数组(矩阵)的列的元素。
#include <stdio.h>

int *findTargetSubArray(int (*parray)[4],int target){
    
    
    return (int *)parray+target;
}
int main() {
    
    
    int array[3][4] = {
    
    
            {
    
    11,22,33,44},
            {
    
    55,66,77,88},
            {
    
    99,110,220,330},
    };
    int targetNumber;
    int *subArray;
    puts("输入要查询的行号(0-2)");
    scanf_s("%d",&targetNumber);
    subArray = findTargetSubArray(array,targetNumber);
    for (int i = 0; i < 4; i++) {
    
    
        printf("%d ",*subArray++);
    }
}

在这里插入图片描述

(4)各种"妖魔鬼怪"的定义(经典笔试题):

  • 建议复制到IDE中,练练手

1.定义一个整型数
2.定义一个指向整型数的指针
3.定义一个指向指针的指针,它指向的指针指向一个整型数
4.定义一个有10个整型数的数组
5.定义一个有10个指针的数组,每个指针指向一个整型数
6.定义一个指向有10个整型数的数组的指针
7.定义一个指向指针的指针,被指向的指针指向一个有10个整型数的数组
8.定义一个指向数组的指针,数组中有10个整型指针
9.定义一个指向函数的指针,该函数只有一个整型参数且返回一个整型数
10.定义一个有10个指针的数组,每个数组指向一个函数,该函数只有一个整型参数且返回一个整型数
11.定义一个函数指针,指向的函数有两个整型参数且返回一个函数指针,返回的函数指针指向有一个整型参数且返回整型数的函数

定义一个整型数 int a;
定义一个指向整型数的指针 int *a;
定义一个指向指针的指针,它指向的指针指向一个整型数 int **a;
定义一个有10个整型数的数组 int a[10];
定义一个有10个指针的数组,每个指针指向一个整型数 int *p[10];
定义一个指向有10个整型数的数组的指针 int (*p)[10];
定义一个指向指针的指针,被指向的指针指向一个有10个整型数的数组 int *(*p)[10];() / int (**a)[10];(对)
定义一个指向数组的指针,数组中有10个整型指针 int *((*p1)[10]);(我的答案) / int *(*p2)[10];(参考答案)
定义一个指向函数的指针,该函数只有一个整型参数且返回一个整型数 int (*p)(int);
定义一个有10个指针的数组,每个数组指向一个函数,该函数只有一个整型参数且返回一个整型数 int (*p[10])(int);
定义一个函数指针,指向的函数有两个整型参数且返回一个函数指针,返回的函数指针指向有一个整型参数且返回整型数的函数 int(* (*p)(int,int))(int)
  • 关于第8题:第8题属实有些不理解,我还是觉得int *(( *p1)[10]);和 int *( *p2)[10];是一样的。希望有大佬解惑!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_54429787/article/details/129371459