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这个指针存放的内容转成地址打印出来, 当然是相同的.

最后, 脑子里有一副内存的图就比较好理解了.
目录
相关文章
|
27天前
|
C# Python
Python Tricks : Function Argument Unpacking
Python Tricks : Function Argument Unpacking
15 1
|
3月前
解决微软云Azure Function运行报错-Value cannot be null. (Parameter ‘provider‘)
解决微软云Azure Function运行报错-Value cannot be null. (Parameter ‘provider‘)
73 4
|
3月前
|
C++ Python
【Azure 应用服务】Azure Function Python函数部署到Azure后遇见 Value cannot be null. (Parameter 'receiverConnectionString') 错误
【Azure 应用服务】Azure Function Python函数部署到Azure后遇见 Value cannot be null. (Parameter 'receiverConnectionString') 错误
|
3月前
|
Windows
【Azure 应用服务】Azure Function (PowerShell) 执行时报错 "out of memory"
【Azure 应用服务】Azure Function (PowerShell) 执行时报错 "out of memory"
|
3月前
|
JavaScript 前端开发 C++
【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
|
5月前
|
监控 Serverless Shell
函数计算操作报错合集之 显示"Function timed out after 30 seconds (maxMemoryUsage: 73.38MB)" ,该如何解决
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
成功解决TypeError: ‘encoding’ is an invalid keyword argument for this function
成功解决TypeError: ‘encoding’ is an invalid keyword argument for this function
|
PHP
漏刻有时环境部署:php安装提示Can‘t use function return value in write context
漏刻有时环境部署:php安装提示Can‘t use function return value in write context
64 0
|
数据可视化 PHP
漏刻有时数据可视化大屏常见问题(1): Can’t use function return value in write context
漏刻有时数据可视化大屏常见问题(1): Can’t use function return value in write context
65 0
|
计算机视觉
cv2.error: OpenCV(4.5.2) : -1 : error: (-5:Bad argument) in function ‘rectangle‘
cv2.error: OpenCV(4.5.2) : -1 : error: (-5:Bad argument) in function ‘rectangle‘
434 0

热门文章

最新文章