数组传参的特殊性,数组指针,函数指针

本文深入探讨了C语言中指针与数组的关系及应用技巧,包括如何通过指针改变数组内容、数组指针的概念及其陷阱、以及如何利用指针进行数组排序等。文章还介绍了函数指针的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我不困,我只是趴一下。”—-叶瑞达

遗漏的知识点:

#include<stdio.h>
void fun(int *p)
{
    printf("%d\n",p[5]);
    getchar();
}
void main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
    fun(&a[3]);
}

上述代码中:p[i],相当于将传进去的地址,像后偏移5位后取值。

改变一级指针的指向(直接改变):
void main2(int * p )
{
int *p2 = p;(int *p2; p2 = p)
*p2 = 100;
}

通过二级指针改变一级指针的指向(间接改变):
void main1(int *p)
{
int **p = &p;
**p = 200;
}

- - - - - - - - - - - - - - - - - -今日内容 - - - - - - - - - - - - - - - - - - - - -

数组传参特殊性:

在此之前我们知道形参值的改变不会影响实参的值,但是数组是个例外。当数组作为参数传递给函数时,形参并没有另外开辟空间,而是直接在原数组的地址上操作。如果函数内更改了数组元素的值,那么原函数也会修改,这样是为了节省内存。代码演示如下:

#include<stdio.h>
int i =0;
void print(int a[]) 
{
    for(i = 0;i < 5;i++)
    {
        printf("%d\n",a[i]);   //1,3,9,11,23
    }
    a[2] = 100;

}
void main()
{
    int a[5] = {1,3,9,11,23};   
    print(a);
    for(i = 0;i < 5;i++)
    {
        printf("%d\n",a[i]);  //1,3,100,11,23
    }
    getchar();
}

数组指针

前方有坑,需要注意

int a[2][3] = {{1,2,3},{4,5,6}};
a,指向的是整个数组,默认指向第一行的地址a[0]。
a[0],指向的是第一行,默认指向第一行第一个元素的地址a[0][0]。
a[0][0],指向第一行第一个元素的地址a[0][0],不需要默认就是。
因为a[0][0]在a[0] 里,a[0]在a里,虽然他们在内存里各自的存储空间长度不同,但是起点是一样且重合的。所以在昨天打印时会得到:
a = &a = *a = a[0] = &a[0] = &a[0][0] 的结果。

但是取值的时候切不可将他们认为他们可以一样使用:
因为*a等同于a[0],依然是一个地址。
*(&a)是取地址的地址的值,依然是一个地址。
&(*a)是取地址的值的地址,还是个地址。
所以要取数组第一个元素的正确方式应该是:

*(*a)或者*a[0]或者*a[0][0]

总的来说二维数组,要取值就必须指向具体地址。所谓具体,就是指向的内存区域大小刚好只够储存唯一个值,或者说精确到多维数组最高维数组里单个元素的地址。可以这么认为:
a+默认 = a[0], 所以*a取不到a[0][0]的值,因为它还是个地址。
a[0] + 默认 = &a[0][0] ,所以*a[0]可以取到a[0][0]的值,

一维数组:a[5] = {1,2,3,4,5};
int *p = a; (合法)
int *p = &a;(合法)
int *p = a[0];(合法)
int *p = &a[0];(合法)

二维数组:a[3][4] = {{1,2,3,4},{5,6,7,8},{11,22,33,44}}
int *p = a; (不合法)
int *p = &a;(不合法)
int *p = a[0];(合法)
int *p = &a[0];(不合法)
int *p = &a[0][0];(合法)

int (*p)[4] = a (合法) 代表指针指向的是一个列数为4的二维数组

上一篇有这样一个公式:*(*(a + i) + j) = a[i][j],等同于*(*(p + i) + j)
a只能参与+运算,和-运算。不能参与++和–运算,因为a的地址是个常量。但是p可以,这是它存在的一个很重要的意义。
另外注意这里的指针变量p,只有按int (*p)[4] = a这种格式定义才能实现跨行功能,其它合法格式定义的P都只能逐个移动下标。

用指向数组的指针作为函数参数

#include <stdio.h>
int i = 0, j = 0;
int a[10];
int *p1 = &a[0];

change(int a[10],int *p)
{
    for(i = 0;i < 10; i++)
    {
        for(j = 1;j < 10;j++)
        {
            if(*(p+j) > *(p + j - 1))
            {
                int t;
                t = *(p+j);
                *(p+j) = *(p + j - 1);
                *(p + j - 1) = t; 
            }
        }
    }
}

void main()
{
    printf("\n\n以下是随机生成的数组:\n");
    for(i = 0;i < 10;i++)
    {   
        a[i] = rand()%100+1;
        printf("%d  ",a[i]);
    }
    change(a,p1);
    printf("\n\n经过排序后:\n");
    for(i = 0;i < 10;i++)
    {   
        printf("%d  ",a[i]);
    }
    getchar();
}

函数指针

1,函数指针定义初始化
1)把函数考入到我们调用个main函数里面
2)挖掉函数名,把函数名改成*+函数指针标识符,其它部分原封不动。
就像这样:int(*p)(int a,int b)
2,把*p指一个函数地址。(函数名指向的就是函数存储区域的首地址 )
3,调用格式:p(实参1,实参2).

废话不多说,上代码:

输入两三个数,输出较大值或较小值
# include<stdio.h>
int i = 0,j = 0,k = 0;m = 0,n = 0,max = 0,min = 0;
int m1(int a,int b,int c)
{   
    m = a > b ? a : b;
    max = m > c ? m : c;
    return max;
}
int m2(int a,int b,int c)
{
    n = a < b ? a : b;
    min = n < c ? n : c;
    return min;

}
void main()
{
    int (*p1)(int a,int b,int c);   //Windows下这两条必须放在函数第一行
    int (*p2)(int a,int b,int c);   //Windows下这两条必须放在函数第一行
    printf("任意输入三位数字:\n");
    scanf("\n%d\n%d\n%d",&i,&j,&k);
    getchar();      
    p1 = m1;        //初始化
    p2 = m2;    //初始化
    printf("\n最大值是:   %d",p1(i,j,k));       //函数指针的调用 
    printf("\n最小值是:   %d",p2(i,j,k));       //函数指针的调用
    getchar();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值