function's argument is function's local variable, build in stack memory, released when function exit. its value copyed from out variables.

C的函数, 如果它有参数. 参数是怎么传递的.
有这么几点必须明白:

1. 参数传递时, 函数体内部将在内存stack区域新建作用在这个函数内部的本地变量.

如 void test1 (char * a) , 这里 a 是函数的本地变量. 

2. 传递的是值, 而不是变量.

如 test1(b), 函数体里面的 a 是拷贝了b这个变量的值, 而不是b这个变量.

来做个测试就会明白 : 

[root@digoal zzz]# cat a.c
#include <stdio.h>
#include <string.h>

int main() {
typedef struct fish {
  int age;
  char name[10];
} fish;

char * gt1 = "abcdefg";
char gt2[10] = "abcdefg";
int gt3 = 100;
fish gt4 = {20, "linux"};

void test1 (char * t1) {
  fprintf(stdout, "&t1:%p, t1:%p, >1:%p, gt1:%p\n", &t1, t1, >1, gt1);
}

void test2 (char t2[]) {
  fprintf(stdout, "&t2:%p, t2:%p, >2:%p, gt2:%p\n", &t2, t2, >2, gt2);
}

void test3 (int t3) {
  fprintf(stdout, "&t3:%p, >3:%p\n", &t3, >3);
}

void test4 (struct fish t4) {
  fprintf(stdout, "&t4:%p, >4:%p\n", &t4, >4);
}

  test1(gt1);
  test2(gt2);
  test3(gt3);
  test4(gt4);
  return 0;
}
结果 :
[root@digoal zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
&t1:0x7fff08f00b10, t1:0x400748, >1:0x7fff08f00ad0, gt1:0x400748  // 字符串在这里是常量放在constants内存区域, 所以地址比较小. 而变量放在stack区域, 所以地址比较大 .
&t2:0x7fff08f00b10, t2:0x7fff08f00aec, >2:0x7fff08f00aec, gt2:0x7fff08f00aec   // 这里要特别注意, 函数体内存储的是个指针变量, 不是数组, 这个指针指向了外部的数组 .
&t3:0x7fff08f00b1c, >3:0x7fff08f00ae8
&t4:0x7fff08f00b00, >4:0x7fff08f00ad8
// 这里我分别测试了指针变量,数组,int型以及结构体 . 

结果表明 : 

1. 指针变量作为参数类型时, 传递的是指针存储的地址值. 而指针变量的地址是不一样的, 因为在函数体内的t1的地址与gt1地址不一致.

2. 数组作为参数类型时(这里要注意, 数组作为参数变量, 这个变量在函数体内部是指针, 也就是失去了数组的特性), 

    传递的是外部数组gt2的地址, 所以地址 (t2 = &gt2 = gt2),  (因为数组变量名在编译时替换成地址). 参数变量的地址与参数变量存储的地址不一致. 也说明了参数变量虽然是数组. 但是显然它在函数体内其实是指针. 如果是数组的话, &t2 应该等于 t2.

3. int作为参数类型时, 传递的是值. 可以看到&t3 不等于 &gt3

4. 结构体作为参数类型时, 传递的也是值. 可以看到&t4 不等于 &gt4 . 

5. &t1 = &t2 又是为什么呢, 前面说了 函数体内部的变量都放在stack里面, 当函数调用结束就会释放掉, 所以test1 执行完再执行test2 是有可能申请到同一片stack里面的地址的.

另外要说的是 , 由于是拷贝, 所以我们要特别注意变量存储的是什么东西. 如参数类型是指针, 拷贝过去就是这个指针存储的地址. 所以他们会指向同一个地方。

所以如果结构体中如果有使用数组存储的, 或者指针存储的元素, 他们拷贝的内容是大不一样的.

例如 : 

[root@digoal zzz]# cat a.c
#include <stdio.h>
#include <string.h>

int main() {

typedef struct fish {
  int age;
  char name[10];
  char * nick;
} fish;

fish gt4 = {20, "linux", "world"};

void test4 (struct fish t4) {
  fprintf(stdout, "&(t4.name):%p, &(gt4.name):%p, t4.name:%p, gt4.name:%p\n", &(t4.name), &(gt4.name), t4.name, gt4.name);
  fprintf(stdout, "&(t4.nick):%p, &(gt4.nick):%p, t4.nick:%p, gt4.nick:%p\n", &(t4.nick), &(gt4.nick), t4.nick, gt4.nick);
}

  test4(gt4);
  return 0;
}
结果
[root@digoal zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a
&(t4.name):0x7fffed837484, &(gt4.name):0x7fffed8374a4, t4.name:0x7fffed837484, gt4.name:0x7fffed8374a4
&(t4.nick):0x7fffed837490, &(gt4.nick):0x7fffed8374b0, t4.nick:0x4006e8, gt4.nick:0x4006e8

来解释一下 : 

1. &(t4.name):0x7fffed837484, &(gt4.name):0x7fffed8374a4 这两个指存放name这个元素的地址. 它们不相等, 是因为函数函数传参是新建本地变量与值拷贝的过程. 所以t4和gt4是放在两块内存区域的, 因此t4和gt4的name它们的存放地当然不一样.

2. t4.name:0x7fffed837484, gt4.name:0x7fffed8374a4 这两个不一样, 因为t4在函数内部是一个全新的结构体变量, 所以t4.name 存储的是数组本身, 而没有退化成指针, 所以拷贝的是数组的内容. 因此可以看出&(t4.name) = t4.name ; &(gt4.name) = gt4.name. 因为数组即地址(多次提到).

3. &(t4.nick):0x7fffed837490, &(gt4.nick):0x7fffed8374b0 这两个不相等 . 和第一条的解释一样.

4. t4.nick:0x4006e8, gt4.nick:0x4006e8 这两个指的是nick这个指针存放的内容转成地址打印出来, 当然是相同的.

最后, 脑子里有一副内存的图就比较好理解了.

时间: 2024-10-09 19:24:13

function's argument is function's local variable, build in stack memory, released when function exit. its value copyed from out variables.的相关文章

【Python】UnboundLocalError: local variable &#039;l&#039; referenced before assignment

01 在程序中设置的sum_Logical属于全局变量,而在函数 calculate中没有sum_Logical的定义,根据python访问局部变量和全局变量的规则:当搜索一个变量的时候,python先从局部作用域开始搜索,如果在局部作用域没有找到那个变量,那样python就在全局变量中找这个变量,如果找不到抛出异常(NAMEERROR 或者 Unbound-LocalError,这取决于python 版本.) 02 如果内部函数有引用外部函数的同名变量或者全局变量,并且对这个变量有修改.那么p

visual studio-在VS2015中实现&amp;amp;quot;Assign to local variable&amp;amp;quot;(自动生成返回值对应变量)?

问题描述 在VS2015中实现"Assign to local variable"(自动生成返回值对应变量)? 在eclipse中,如果我输入 new String(); 然后按下Ctrl + 2l快捷键,那么会得到: String string = new String(); 现在我想知道使用VS2015有没有可能实现这个功能?或者什么插件能做到这一点吗?求大神~~~~~~~~~~~~~~~ 解决方案 VS中没有这一类插件.

sqlconnection-为什么会有use of unassigned local variable &amp;amp;#39;result&amp;amp;#39;

问题描述 为什么会有use of unassigned local variable 'result' internal void check(string name,ref string result) { object pass; SqlConnection con = new SqlConnection("Data Source=SAMSUNG;Initial Catalog=AL_Nayesh_Kids_Castle;Persist Security Info=True;User ID=

分页-Duplicate local variable page

问题描述 Duplicate local variable page 用jsp做分页时, int page = 1;表示当前页, 解决方案 Duplicate local variable messageDuplicate local variable sessionDuplicate local variable sql 解决方案二: 不是很明确变量定义重复了,检查一下是不是定义了两次page

Mapping High-Level Constructs to LLVM IR

原文地址:http://llvm.lyngvig.org/Articles/Mapping-High-Level-Constructs-to-LLVM-IR Mapping High-Level Constructs to LLVM IR Table of Contents Introduction A Quick Primer Some Useful LLVM Tools Mapping Basic Constructs to LLVM IR Global Variables Local Va

Lua code compilation

Lua 虽然是脚本解释语言, 在运行前需要预编译, 同时lua还支持代码预加载操作, 预编译操作等.  在lua代码中  1. 使用load可以将文本转换成匿名函数,  2. 使用loadfile可以将外部文件转换成匿名函数. 3. 匿名函数可以赋予给一个变量然后调用, 或者直接使用()调用. > a=1 > load("a=a+1 print(a)") () 2 > f=load("a=a+1 print(a)") > f() 3 load

通过压缩SOAP改善XML Web service性能

web|xml|性能|压缩 压缩文本是一个可以减少文本内容尺寸达80%的过程.这意味着存储压缩的文本将会比存储没有压缩的文本少80%的空间.也意味着在网络上传输内容需要更少的时间,对于使用文本通信的客户端服务器应用程序来说,将会表现出更高的效率,例如XML Web services. 本文的主要目的就是寻找在客户端和服务器之间使交换的数据尺寸最小化的方法.一些有经验的开发者会使用高级的技术来优化通过网络特别是互联网传送的数据,这样的做法在许多分布式系统中都存在瓶颈.解决这个问题的一个方法是获取更

PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-3 代码组织和重用2

从本章中,我们了解 .创建可以调用的函数以便重用代码 .把参数传递给函数并且从函数返回值和脚本的不同部分中的变量和数据进行交互 .把代码和函数组存入到其他文件中,并且我们的脚本内包含这些文件. 3.1基本代码重用:函数 3.1.1 定义和调用函数 关键字function通知php这是一个函数,后面跟着的是函数的名称,它可以是字母.数字.字符或下划线 函数名称之后是参数列表,然后是函数体.在其它语言中名称相同.但是参数列表不同的函数,php不支持这一特性. 复制代码 代码如下: <?php fun

JAVASCRIPT的一些知识点梳理

春节闲点,可以安心的梳理一下以前不是很清楚的东东.. 看的是以下几个URL: http://web.jobbole.com/82520/ http://blog.csdn.net/luoweifu/article/details/41466537 http://javascriptissexy.com/understand-javascript-closures-with-ease/ http://javascriptissexy.com/javascript-variable-scope-an