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

来源:互联网 发布:胶州加工中心编程招聘 编辑:程序博客网 时间:2024/06/08 08:57

- - - - - - - - - - - - - - - 触控未来的日子–Day 41- - - - - - - - - - -

早会,闫梦州,诗朗诵。《假如生活欺骗了你》–普希金。
今日笑梗:“我不困,我只是趴一下。”—-叶瑞达

昨天遗漏的知识点:

#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();}
0 0