博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言8
阅读量:4123 次
发布时间:2019-05-25

本文共 3519 字,大约阅读时间需要 11 分钟。

一、数组作为参数/返回值情况是怎样的?内存是怎么变化?

1、回顾学习过的传参情况。
例子1: 传递一个int类型的数据。
void fun(int x) //x = a

int a;

fun(a);  -> 传递了整个a的值过去。

例子2: 传递普通指针过去。

void fun(int *x) // x = p

int a;

int *p = &a;
fun(p);  -> 传递了整个p的值过去。

例子3: 传递函数过去。

void fun(void(*p)(int)) // p = my_fun

void my_fun(int a)

fun(my_fun);   -> 传递了函数的地址过去。

2、传递一个数组,情况会怎么样?

void fun(int *x)  //x = A = &A[0]  -> 首元素的地址类型:int*, 所以需要使用int*的变量去接住这个地址
void fun(int x[3])//这种写法是正确,但是看起来好想把整个数组都传递过来,实际只是传递了首元素的地址
void fun(int x[])
{

}

int main(int argc,char *argv[])

{
    int A[3] = {1,2,3};
    fun(A);  -> 数组名A在这里不是作用于sizeof,所以代表的是首元素的地址  &A[0]

    等价于 fun(&A[0]);  

}

  结论: 数组作为实参时,其实是传递了数组首元素的地址过来。

  练习1: 完成9、10题。

3、数组作为函数的返回值,情况是如何的?

#include <stdio.h>

int *fun()

{
    int i;
    int A[5] = {1,2,3,4,5};
    for(i=0;i<5;i++)
    {
        printf("A[%d]:%d\n",i,A[i]);
    }

    return A;

}

int main(int argc,char *argv[])

{
    int i;        
    int *A = fun();
    for(i=0;i<5;i++)
    {
        printf("A[%d]:%d\n",i,A[i]);
    }
    return 0;
}

编译: warning: function returns address of local variable

    //你要返回一个地址可以,但是这个地址上的东西可能会失效。

结果:
1,2,3,4,5
段错误。  -> 因为数组返回时,只是返回数组的首元素的地址,因为返回之后,数组所在的空间就会被释放,所以64位不会返回数组首元素的            地址,而是会返回NULL。

解决方案: 

1)将数组设置为全局变量。
int A[5] = {1,2,3,4,5};   -> 数组在fun()返回时,不会释放。
int *fun()
{
    int i;
    for(i=0;i<5;i++)
    {
        printf("A[%d]:%d\n",i,A[i]);
    }
    printf("A = %p\n",A);
    return A;
}

2)在数组定义前面加static关键词进行修饰

int *fun()
{
    int i;
    static int A[5] = {1,2,3,4,5};   -> 加了static关键词之后,数组就不会在栈区申请空间,而是在data区申请空间,也就是说函数返回时,该数组的空间不会释放。
    for(i=0;i<5;i++)
    {
        printf("A[%d]:%d\n",i,A[i]);
    }
    printf("A = %p\n",A);
    return A;
}

二、二维数组。

1、什么是二维数组?
二维数组在内存中是线性排列,不存在行与列的关系。
其实二维数组也是一个一维数组来的,只是这个一维数组中每一个成员都是一个一维数组。

例如:

整型数组: int A[5]   -> 每一个成员都是int类型的数据。
二维数组: 数组 A[5]  -> 每一个成员都是一个数组。

2、定义数组,只需要交代两件事情。

1)数组元素的个数
2)每一个数组元素的数据类型。  -> 基本数据类型/非基本数据类型

定义数组的步骤:

例如1: 定义具有5个int类型数据的数组。

第一步:确定一个数组名                                     A

第二步:确定数组中元素的个数,使用[]括住他,跟在数组名后面   A[5]
第三步:确定数组中每一个成员是什么                          int a
第四步:将第3步的结果的变量名去掉                           int
第五步:将第4步的结果写在第2步结果的前面就可以               int A[5]   -> 最终结果。

例子2: 定义一个二维数组,有2个成员,每一个成员都是具有3个int类型的数据。

第一步:确定一个数组名                                     B

第二步:确定数组中元素的个数,使用[]括住他,跟在数组名后面   B[2]
第三步:确定数组中每一个成员是什么                         int x[3]
第四步:将第3步的结果的变量名去掉                          int [3]
第五步:将第2步的结果写在第4步的结果的中间                    int B[2][3]   -> 最终结果。

分析:int B[2][3]

代表这个数组有2个成员,每一个成员都是具有3个int类型的数组。

3、二维数组的赋值。

1)定义的同时初始化。
int B[2][3] = {
{1,2,3},{4,5,6}};

2)先定义,后初始化。

int B[2][3];
B[0][0] = 1;
B[0][1] = 2;
B[0][2] = 3;
B[1][0] = 4;
B[1][1] = 5;
B[1][2] = 6;

4、研究二维数组的名字。

&B  -> 二维数组的地址                                      类型: int (*)[2][3]
B   -> 二维数组的首元素的地址                 -> &B[0]     类型:  int (*)[3]
B[0]-> 二维数组的首元素的首元素的地址         -> &B[0][0]   类型:  int *
B[0][0] -> 二维数组的首元素的首元素的值                     类型:  int

5、解引用。

1)解引用二维数组的名字,得到什么?
int B[2][3] = {
{1,2,3},{4,5,6}};
*B = *&B[0] = B[0] = &B[0][0]   -> 二维数组的首元素的首元素的地址。

2)解引用二维数组的首元素的名字,得到什么?

*B[0] = *(&B[0][0]) = B[0][0]  -> 二维数组的首元素的首元素的值。

#include <stdio.h>

int main(int argc,char *argv[])

{
    int B[2][3] = {
{1,2,3},{4,5,6}};
    
    printf("&B = %p\n",&B);  //int(*)[2][3]
    printf("B = %p\n",B);    //int(*)[3]
    printf("B[0] = %p\n",B[0]); //int*
    
    printf("&B+1 = %p\n",&B+1);  //int(*)[2][3]
    printf("B+1 = %p\n",B+1);    //int(*)[3]
    printf("B[0]+1 = %p\n",B[0]+1); //int*
    
    return 0;
}

   练习2: 完成11、12、13题。

三、指针数组。

1、什么是指针数组?什么是数组指针?
数组指针是一个指针来的,这个指针指向一个数组的。
指针数组是一个数组来的,这个数组中每一个元素都是一个指针。

2、如何定义指针数组?

例如1: 定义具有5个int类型数据的数组。

第一步:确定一个数组名                                     A

第二步:确定数组中元素的个数,使用[]括住他,跟在数组名后面   A[5]
第三步:确定数组中每一个成员是什么                          int a
第四步:将第3步的结果的变量名去掉                           int
第五步:将第4步的结果写在第2步结果的前面就可以               int A[5]   -> 最终结果。

例子2: 定义具有5个int*类型变量的数组。

第一步:确定一个数组名                                     B

第二步:确定数组中元素的个数,使用[]括住他,跟在数组名后面   B[5]
第三步:确定数组中每一个成员是什么                          int*p
第四步:将第3步的结果的变量名去掉                           int*
第五步:将第4步的结果写在第2步结果的前面就可以               int *B[5]   -> 最终结果。

分析:int *B[5]

数组名: B
成员个数: 5
每一个成员的类型: int*

3、请问以下两句话的含义是什么?

  int *p[5]   ->  这是一个指针数组,这个数组中每一个成员都是int*类型的。

  int (*p)[5]  -> 这是一个数组指针,这个指针用于指向一个具有5个int类型数据的数组。

 

 

转载地址:http://emmpi.baihongyu.com/

你可能感兴趣的文章
解决"Ubuntu系统Pycharm安装pygame报错"问题
查看>>
解决已安装opencv但仍提示报错“no module named cv2“问题
查看>>
解决“can‘t find starting number (in the name of file)“问题
查看>>
解决“fatal error: dynlink_nvcuvid.h: 没有那个文件或目录#include <dynlink_nvcuvid.h>“问题
查看>>
Ubuntu 18.04安装OpenCV
查看>>
Ubuntu 18.04 安装labelImg与使用
查看>>
解决“WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!”问题
查看>>
在Linux服务器上安装Anaconda步骤
查看>>
Linux服务器安装Python3.7.5心路历程
查看>>
为Linux服务器conda添加清华镜像
查看>>
解决“The channel is not accessible or is invalid”问题
查看>>
解决下载Github项目速度过慢的问题
查看>>
在Linux服务器上安装Pytorch1.5.1版本
查看>>
向Linux服务器传输文件
查看>>
解决“tensorboard报错”问题
查看>>
配置服务器CV实验环境之缺啥装啥
查看>>
解决“RuntimeError: expected backend CUDA and dtype Float but got backend CUDA and dtype Half”问题
查看>>
解决“E505:“/usr/bin/yum“ is read-only(add !to override)”问题
查看>>
解决“ImportError: libGL.so.1”问题
查看>>
解决“ImportError: libgthread-2.0.so.0”问题
查看>>