从数组传参看函数的调用和数组的存储情况

2024-08-24 01:32

本文主要是介绍从数组传参看函数的调用和数组的存储情况,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先我们先上例程:

#include <stdio.h>#define SIZE 10
/* 数组为 int 类型的数组*/
const int date[SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int Sum(unsigned char *ar);void main( void )
{int date_sum = 0;date_sum = Sum(date);printf("将数组的数相加等于:%d\n", date_sum);
}/*形参为 unsigned char 类型
*/
int Sum(unsigned char *ar)
{int i;int total = 0;/* 先打印出 ar 的地址*/printf("ar(a[0])的首地址:%x\n\n", ar);for(i=0; i<SIZE; i++){/* 打印出数组的地址和值*/printf("数组ar[%d]地址:%x    值:%d\n", i, &ar[i], ar[i]);total += ar[i];}return total;
}

运行结果为:


本应输出的结果应为:0+1+···+9 = 45

而实际输出的结果却为3,这是为什么呢,让我们先看看函数调用的过程。


函数调用过程:

                                                                        

调用函数首先把参数放在堆栈的临时存储区域中,然后被调函数从堆栈中读取这些参数。但这两个过程并没有相互协调进行,调用函数传递的是实参的类型,而被调用函数则是按照其形参的类型进行数据读取。

从函数调用的原理我们可以看出:调用函数先将 int 类型的数组data[SIZE] 放入首地址为 0x00422fa8 的内存当中,我们用 memory 窗口可观察 0x00422fa8 ~ 0x00422fcb 这部分内存所存储的值,因为数组类型为 int 类型,所以一个元素占4个字节


而被调函数则是按形参声明的类型类调用堆栈里的数据的,形参声明的类型是 char 类型,所以形参是 1字节1字节 的调用堆栈里的数据的,所以程序 for 循环中调用了10次数组的值相加也只是将 0X00422FA8 ~ 0X00422FB1 的值相加而已,所以导致程序得出错误的结果。


而我们将例程中的:

int Sum(unsigned char *ar);
改为:

int Sum(int *ar);

运行的结果为:


则它将会每隔4个字节读取堆栈的数据。


从这个易错的例子我们可以很好的理解:函数调用的过程、数组在内存中的存储、数组和指针等问题。

这篇关于从数组传参看函数的调用和数组的存储情况的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101062

相关文章

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处