参数传址调用 为什么不是双向传送数据传输动画

sponsored links
SAP ABAP开发技术总结Form(subroutine)、Function参数传值传址
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4263707.html
这节也是ABAP学习的关键所在,Form、Function、Method的参数定义都差不多,弄懂一个,其他都好办。参数传递涉及传值、传址问题,这是其也语言也有的问题,要学好他,你得要仔细想想
&&&&&&&&&&
Function Group
&&&&&&&&&&
参数传值、传址
Function Group
Function Builder
创建函数组时,系统会自动创建
main program
Function Group
SAPL&fgrp&
为主程序名,它将
Function Group
文件包括进来,除了
语句之外,没有其他语句了
L&fgrp&TOP
FUNCTION-POOL
语句,以及所有
Function Module
都可以使用的全局数据定义
L&fgrp&UXX
语句,它所包括的
文件为相应具体
Function Module
L&fgrp&U01
L&fgrp&U02
文件实际上包含了所对应的
Function Module
代码(即双击它们进去就是对应的
,而显示的不是真正
文件所对应的代码)
L&fgrp&U01
L&fgrp&U02
L&fgrp&UXX
&,代表其创建先后的序号,例如
L&fgrp&U01
L&fgrp&U02
是头两个被创建的函数,在函数组中创建出的函数代码就放在相应的
L&fgrp&UXX
代表某个数字,而不是字面上的
L&fgrg&FXX
,用来存一些
子过程,并且可以
Function Modules
所使用(不是针对某个
Function Module
的,但一般在设计时会针对每个
Function Module
设计这样单独的
文件,这是一个好习惯),并且在使用时不需要在
Function Module
语句包含它们(因为这些文件在主程序
SAPL&fgrp&
里就已经被
进来了)。另外,
L&fgrg&FXX
的意思,这是一种名称约束而已,在创建时我们可以随便指定,一般还有
(表示些类
文件包括的是一些
事件中调用的
,有时干脆直接使用
L&fgrg&PAI
(表示些类
文件包括的是一些
事件中调用的
,有时干脆直接使用
L&fgrg&PBO
)。注:如果
只被某一函数单独使用,实质上还可直接将这些
Function Module
ENDFUNCTION
当你调用一个
function module
时,系统加将整个
function group
Function Module
文件等)加载到主调程序所在的
参数传值、传址
*"*"Local Interface:
*"& IMPORTING
(I_I1) TYPE& I
为参数的默认传递类型
(I_I2) TYPE& I&&&&&&&
定义时勾选了
Pass Value
选项才会是
*"&&&& REFERENCE(I_I3)
*"&&&& VALUE(I_I4)
*"& EXPORTING
*"&&&& REFERENCE(E_I1) TYPE& I
*"&&&& VALUE(E_I2) TYPE& I
*"&&&& REFERENCE(E_I3) TYPE REF TO& I
*"&&&& VALUE(E_I4) TYPE REF TO& I
*"& TABLES
*"&&&&& T_1 TYPE& ZJZJ_ITAB
*"& CHANGING
*"&&&& REFERENCE(C_I1) TYPE& I
*"&&&& VALUE(C_I2) TYPE& I
*"&&&& REFERENCE(C_I3) TYPE REF TO& I
*"&&&& VALUE(C_I4) TYPE REF TO& I
为输入类型参数
且又是引用类型
实参不能被修改
中的引用(别名)参数方式传递参数,所以如果修改了
就会修改实际参数,所以函数中不能修改
类型的参数,如果去掉下面注释则编译出错
"i_i1 = 10.
是输入类型的参数,但不是引用类型,所以可以修改
,编译能通过但不会修改外面实参的值,只是修改了该函数局部变量的值
存储的是地址,所以先要解引用再能使用
类型的参数不能被修改:这里即不能修改实参的指向
"GET REFERENCE OF 30 INTO i_i3."
虽然不可以修改实参的指向,但可以修改实参所指向的实际内容
存储也的是地址,所以先要解引用再能使用
是输入类型的参数,但不是引用类型,所以可以修改,只会修改函数中的局部参数
的指向,但并不会修改实参的指向
虽然不能修改实参的指向,但可以直接修改实参的所指向的实际内容
为实参的别名,修改形参就等于修改实参内容
为实参的副本,所以不会影响实参的内容,但是,
类型的参数
且为值传递
,在函数正常执行完后,还是会将该副本再次拷贝给实参,所以最终实参还是会被修改
ENDFUNCTION
调用程序:
&&&&& i_i2
&&&&& i_i3
&&&&& i_i4
&&&&& c_i1
&&&&& c_i2
&&&&& c_i3
&&&&& c_i4
&&& i_i1 = i_i1
&&& i_i2 = i_i2
&&& i_i3 = i_i3
&&& i_i4 = i_i4
&&& t_1 = t_1
&&& c_i1 = c_i1
&&& c_i2 = c_i2
&&& c_i3 = c_i3
&&& c_i4 = c_i4.
: / i_i3_.
: / i_i4_.
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4260224.html
该文档是根据我过去多年学习与 ...
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4264698.html OPEN SQL也是ABAP开发 ...
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4265581.html 19.
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4264685.html 内表是每个ABAP开发人员都必须 ...
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4265588.html FTP文件到文件服务器服务器上文 ...C语言 内存分配 地址 指针 数组 参数 实例解析
void 与 void
1 void 简介
2 void简介
C 语言 程序内存分配
1 内存分区状况
2 内存分配方式
3 register变量
4 extern 变量
5 static变量 与 全局变量区别
6 堆 和 栈比较
7 各区分布情况
指针与地址
2 指针定义解析
3 指针运算及示例
函数参数的传值调用和传址调用
1 传值调用 和 传址调用
2 高级示例
指针 和 数组
—————————————————————–
指针简介 : 指针式保存变量地址的变量;
– 增加阅读难度 : 指针 和 goto 语句会增加程序的理解难度, 容易出现错误;
– ANSI C : American National Standards Institute 美国国家标准学会, 即标准C;
– 通用指针类型 : ANSI C中使用 void* 作为通用指针类型, 即指向void的指针, void 是空类型, void* 是空类型指针, 可以指向任意类型的地址;
1. void 与 void*
(1) void 简介
void 作用 :
– 限定参数 : 函数没有返回值, 需要使用 void 声明, 否则默认返回 int 类型;
– 限定返回值 : 函数不接收参数, 使用 void 作为参数, 如果传入参数, 编译器就会报错;
使用void注意点 :
– void不能表示变量 : void a, 这样定义是错误的;
– 默认返回值 : C 中, 如果没有标明返回值类型, 默认的返回值不是 void, 是 int 类型;
– void参数 : C 语言中参数是void, 传入参数不会出错, C++中传入参数会出错, 因此这里我们统一规定, 如果函数没有参数, 就定义为
(2) void*简介
void * 作用 :
– 通用数据类型 : void * 指针可以存放任意类型数据的地址, 任何数据类型的指针都可以赋值给 void * 通用类型指针;
– 任意类型 : 如果 函数 的 参数 和 返回值 可以是任意类型, 就可以使用 void * 作为函数的 参数 或者 返回值;
使用void* 注意点 :
– void * 与 其它类型互相赋值 : int * 变量可以赋值给 void * 变量, 但是void * 变量如果赋值给 int * 变量需要强转为 int * 类型;
– void * 不允许进行 算数操作 : 标准C 中规定 void * 类型不允许进行 加减乘除 算数运算, 因为我们不知道这个类型的大小, GUN 中void * 等价于 char * ;
2. C 语言 程序内存分配
(1) 内存分区状况
栈区 (stack) :
– 分配, 释放方式 : 由编译器自动分配 和 释放;
– 存放内容 : 局部变量, 参数;
– 特点 : 具有 后进先出 特性, 适合用于 保存 回复 现场;
堆区 (heap) :
– 分配, 释放方式 : 由程序员手动 分配(malloc) 和 释放(free), 如果程序员没有释放, 那么程序退出的时候, 会自动释放;
– 存放内容 : 存放程序运行中 动态分配 内存的数据;
– 特点 : 大小不固定, 可能会动态的 放大 或 缩小;
堆区内存申请 :
– 申请过程 : OS中有一个记录空闲内存地址的链表, 如果程序员申请内存, 就会找到空间大于申请内存大小的节点, 将该节点从空间内存链表中删除, 并分配该节点;
– 剩余内存处理 : 系统会将多余的部分重新放回 空闲内存链表中;
– 首地址记录大小 : 分配内存的首地址存放该堆的大小, 这样释放内存的时候才能正确执行;
全局区/静态区 (数据段 data segment / bss segment) :
– 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;
– 存放内容 : 全局变量, 静态变量;
– 特点 : 全局变量 和 静态变量存储在一个区域, 初始化的两种变量 和 未初始化的 存储在不同区域, 但是两个区域是相邻的;
– 分配, 释放方式 : 退出程序由系统自动释放;
– 存放内容 : 常量;
代码区 (text segment) :
– 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;
– 存放内容 : 存放 程序的二进制代码, 和一些特殊常量;
内存存放顺序 (由上到下) : 栈区 -& 堆区 -& 全局区 -& 常量区 -& 代码区;
(2) 内存分配方式
全局内存分配 :
– 生命周期 : 编译时分配内存, 程序退出后释放内存, 与 程序 的生命周期相同;
– 存储内容 : 全局变量, 静态变量;
栈内存分配 :
– 生命周期 : 函数执行时分配内存, 执行结束后释放内存;
– 特点 : 该分配运算由处理器处理, 效率高, 但是栈内存控件有限;
堆内存分配 :
– 生命周期 : 调用 malloc()开始分配, 调用 free()释放内存, 完全由程序员控制;
– 谨慎使用 : 如果分配了 没有释放, 会造成内存泄露, 如果频繁 分配 释放 会出现内存碎片;
(3) register变量
使用场景 : 如果 一个变量使用频率特别高, 可以将这个变量放在 CPU 的寄存器中;
– 修饰限制 : 只有 局部变量 和 参数 可以被声明为 register变量, 全局 和 静态的不可以;
– 数量限制 : CPU 寄存器 很宝贵, 不能定义太多register变量;
(4) extern 变量
extern变量概念 : 声明外部变量, 外部变量就是在函数的外部定义的变量, 在本函数中使用;
– 作用域 : 从外部变量定义的位置开始, 知道本源码结束都可以使用, 但是只能在定义extern后面使用, 前面的代码不能使用;
– 存放位置 : 外部变量 存放在 全局区;
extern变量作用 : 使用extern修饰外部变量, ① 扩展外部变量在本文件中的作用域, ② 将外部变量作用域从一个文件中扩展到工程中的其它文件;
extern声明外部变量的情况 :
– 单个文件内声明 : 如果不定义在文件开头, 其作用范围只能是 定义位置开始, 文件结束位置结束;
– 多个文件中声明 : 两个文件中用到一个外部变量, 只能定义一次, 编译 和 连接的时候, 如果没有这个外部变量, 系统会知道这个外部变量在别处定义, 将另一个文件中的外部变量扩展到本文件中;
extern编译原则 :
– 本文件中能找到 : 编译器遇到 extern 的时候, 现在本文件中找外部变量的定义的位置, 如果找到, 就将作用域扩展到 定义的位置 知道文件结束;
– 本文件中找不到 : 如果本文件中找不到, 连接其它文件找外部变量定义, 如果找到, 将外部变量作用域扩展到本文件中;
– 外部文件找不到 : 报错;
使用效果 : extern 使用的时候, 可以不带数据类型;
– 本文件 : int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就扩展为从第一行到文件末尾;
– 多文件 : 在任意文件中定义了 int A = 0; 在本文件中声明 extern A, 那么从当前位置到文件末尾都可以使用该变量;
(5) static变量 与 全局变量区别
static 变量 与 全局变量 相同点 : 全局变量是静态存储的, 存储的方式 和 位置基本相同;
static 变量 与 全局变量不用点 : 全局变量的作用域是 整个项目工程 横跨过个文件, 静态变量的作用域是 当前文件, 其它文件中使用是无效的;
变量存储位置 : 全局变量 和 静态变量 存放在 全局区/静态去, 局部变量存放在 栈区(普通变量) 和 堆区(指针变量);
变量静态化 :
– 局部变量 : 局部变量 加上 static , 相当于将局部变量的生命周期扩大到了整个文件, 作用域不改变;
– 全局变量 : 全局变量 加上 static , 相当于将全局变量的作用域缩小到了单个文件, 生命周期是整个程序的周期;
关于函数头文件的引申 :
– 内部函数 : 单个文件中使用的内部函数, 仅在那个特定文件中定义函数即可;
– 全局函数 : 如果要在整个工程中使用一个全局函数, 需要将这个函数定义在一个头文件中;
static变量与普通变量区别 :
– static全局变量 与 全局变量区别 : static 全局变量 只初始化一次, 防止在其它文件中使用;
– static局部变量 与 局部变量区别 : static 局部变量 只初始化一次, 下一次依据上一次结果;
static函数与普通函数区别 : static 函数在内存中只保留一份, 普通函数 每调用一次, 就创建一个副本;
(6) 堆 和 栈比较
堆(heap)和栈(stack)区别 :
– 申请方式 : stack 由系统自动分配, heap 由程序员进行分配;
– 申请响应 : 如果 stack 没有足够的剩余空间, 就会溢出; 堆内存从链表中找空闲内存;
– 内存限制 : stack 内存是连续的, 从高位向低位扩展, 而且很小, 只有几M, 是事先定好的, 在文件中配置; heap 是不连续的, 从低位向高位扩展, 系统是由链表控制空闲程序, 链表从低地址到高地址, 堆大小受虚拟内存限制, 一般32位机器有4G
– 申请效率 : stack 由系统分配, 效率高; heap 由程序员分配, 速度慢, 容易产生碎片;
(7) 各区分布情况
按照下图分布 : 由上到下顺序 : 栈区(stack) -& 堆区(heap) -& 全局区 -& 字符常量区 -& 代码区;
验证分区状况 :
– 示例程序 :
/*************************************************************************
& File Name: memory.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Mon 10 Mar :12 PM CST
************************************************************************/
#include&stdio.h&
#include&stdlib.h&
int global1 = 0, global2 = 0, global3 = 0;
void function(void)
int local4 = 0, local5 = 0, local6 = 0;
static int static4 = 0, static5 = 0, static6 = 0;
int *p2 = (int*)malloc(sizeof(int));
printf("子函数 局部变量 : \n");
printf("local4 : %p \n", &local4);
printf("local5 : %p \n", &local5);
printf("local6 : %p \n", &local6);
printf("子函数 指针变量 : \n");
printf("p2 : %p \n", p2);
printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3);
printf("子函数 静态变量 : \n");
printf("static4 : %p \n", &static4);
printf("static5 : %p \n", &static5);
printf("static6 : %p \n", &static6);
printf("子函数地址 : \n");
printf("function : %p \n", function);
int main(int argc, char **argv)
int local1 = 0, local2 = 0, local3 = 0;
static int static1 = 0, static2 = 0, static3 = 0;
int *p1 = (int*)malloc(sizeof(int));
const int const1 = 0;
char *char_p = "char";
printf("主函数 局部变量 : \n");
printf("local1 : %p \n", &local1);
printf("local2 : %p \n", &local2);
printf("local3 : %p \n", &local3);
printf("const1 : %p \n", &const1);
printf("主函数 指针变量 : \n");
printf("p1 : %p \n", p1);
printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3);
printf("主函数 静态变量 : \n");
printf("static1 : %p \n", &static1);
printf("static2 : %p \n", &static2);
printf("static3 : %p \n", &static3);
printf("字符串常量 : \n");
printf("char_p : %p \n", char_p);
printf("主函数地址 : \n");
printf("main : %p \n", main);
printf("= = = = = = = = = = = = = = = \n");
function();
– 执行结果 :
/*************************************************************************
& File Name: memory.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Mon 10 Mar :12 PM CST
************************************************************************/
#include&stdio.h&
#include&stdlib.h&
int global1 = 0, global2 = 0, global3 = 0;
void function(void)
int local4 = 0, local5 = 0, local6 = 0;
static int static4 = 0, static5 = 0, static6 = 0;
int *p2 = (int*)malloc(sizeof(int));
printf("子函数 局部变量 : \n");
printf("local4 : %p \n", &local4);
printf("local5 : %p \n", &local5);
printf("local6 : %p \n", &local6);
printf("子函数 指针变量 : \n");
printf("p2 : %p \n", p2);
printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3);
printf("子函数 静态变量 : \n");
printf("static4 : %p \n", &static4);
printf("static5 : %p \n", &static5);
printf("static6 : %p \n", &static6);
printf("子函数地址 : \n");
printf("function : %p \n", function);
int main(int argc, char **argv)
int local1 = 0, local2 = 0, local3 = 0;
static int static1 = 0, static2 = 0, static3 = 0;
int *p1 = (int*)malloc(sizeof(int));
const int const1 = 0;
char *char_p = "char";
printf("主函数 局部变量 : \n");
printf("local1 : %p \n", &local1);
printf("local2 : %p \n", &local2);
printf("local3 : %p \n", &local3);
printf("const1 : %p \n", &const1);
printf("主函数 指针变量 : \n");
printf("p1 : %p \n", p1);
printf("全局变量 : \n");
printf("global1 : %p \n", &global1);
printf("global2 : %p \n", &global2);
printf("global3 : %p \n", &global3);
printf("主函数 静态变量 : \n");
printf("static1 : %p \n", &static1);
printf("static2 : %p \n", &static2);
printf("static3 : %p \n", &static3);
printf("字符串常量 : \n");
printf("char_p : %p \n", char_p);
printf("主函数地址 : \n");
printf("main : %p \n", main);
printf("= = = = = = = = = = = = = = = \n");
function();
– 执行结果 :
[root@ip28 pointer]# gcc memory.c
[root@ip28 pointer]# ./a.out
主函数 局部变量 :
local1 : 0x7fff75f5eedc
local2 : 0x7fff75f5eed8
local3 : 0x7fff75f5eed4
const1 : 0x7fff75f5eed0
主函数 指针变量 :
p1 : 0x19bad010
全局变量 :
global1 : 0x600e14
global2 : 0x600e18
global3 : 0x600e1c
主函数 静态变量 :
static1 : 0x600e34
static2 : 0x600e30
static3 : 0x600e2c
字符串常量 :
char_p : 0x4009f7
主函数地址 :
main : 0x40065f
= = = = = = = = = = = = = = =
子函数 局部变量 :
local4 : 0x7fff75f5eea4
local5 : 0x7fff75f5eea0
local6 : 0x7fff75f5ee9c
子函数 指针变量 :
p2 : 0x19bad030
全局变量 :
global1 : 0x600e14
global2 : 0x600e18
global3 : 0x600e1c
子函数 静态变量 :
static4 : 0x600e28
static5 : 0x600e24
static6 : 0x600e20
子函数地址 :
function : 0x400528
3. 指针与地址
(1) & 与 * 操作
取地址运算符 & : p = &c;
– 表达式解析 : 将 c 的地址赋值给 变量 p, p 是指向 c 变量的指针;
– & 可以使用的情况 : 取地址操作 只能用于内存中的对象, 如变量 或 数组, 栈内存 堆内存 都可以;
– & 不适用的情况 : 不能用于 表达式, 常量, register类型变量;
间接引用运算符 : * ;
– 声明指针 : int * 该表达式的含义是 *p 的结果是 int 类型, 声明变量 a, int a, 声明指针 *p , int *p;
– 获取指针指向的值 : int a = *
(2) 指针定义解析
声明指针 和 函数 : int *p, max(int a, int b), 声明指针变量 语法 与声明 变量语法类似, 同理声明函数也一样;
– 原理 : *p 和 max()返回值 类型都是 int 类型;
指针指向 : 每个指针都必须指向某种特定类型;
– 例外 : void *p 可以指向任何类型, 但是 p 不能进行取值运算, *p 是错误的, 因为不知道 p 指向的数据类型;
(3) 指针运算及示例
指针相关运算 : int x = 0; int *p = &x; 那么*p 就可以代表x;
– 算数运算 : x = x + 1; 等价于 *p = *p + 1 ; int y = x + 1; 等价于 int y = *p + 1;
– 自增运算 : 前提 : ++, * 运算顺序是自右向左;
++*p 和 (*p)++, p 指向的值自增1, 注意要加上括号, 否则会将地址自增;
– 指针赋值 : int *p, *q; int a = 0; p = &a; q = 最终结果 p 和 q 都指向了 变量
示例程序 :
/*************************************************************************
& File Name: pointer_address.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Mon 10 Mar :01 PM CST
************************************************************************/
#include&stdio.h&
int main(int argc, char ** argv)
int *p, *q;
int a = 10,
//p指针指向a变量
//*p 可以代替 a 进行运算
b = *p + 5;
//指针之间可以直接相互赋值
//打印 p 和 q 指针指向的值
printf("*p = %d \n", *p);
printf("*q = %d \n", *q);
执行结果 :
[root@ip28 pointer]# gcc pointer_address.c
[root@ip28 pointer]# ./a.out
4. 函数参数的传值调用和传址调用
(1) 传值调用 和 传址调用
传值调用 : 以传值的方式将参数传递给函数, 不能直接修改主函数中变量的值, 仅仅是将副本传递给了函数;
传址调用 : 将 变量的指针 传递给函数, 当函数对指针进行操作的时候, 主函数中的值也进行了对应变化;
交换函数示例1 :
/*************************************************************************
& File Name: swap.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Mon 10 Mar :18 PM CST
************************************************************************/
#include&stdio.h&
void swap_1(int a, int b)
printf("swap_1 传值 函数 a = %d, b = %d \n", a, b);
void swap_2(int *a, int *b)
temp = *a;
printf("swap_2 传址 函数 a = %d, b = %d\n", *a, *b);
int main(int argc, char **argv)
int a = 10, b = 5;
printf("初始值 : a = %d, b = %d \n\n", a, b);
swap_1(a, b);
printf("执行 swap_1 函数, a = %d, b = %d \n\n", a, b);
swap_2(&a, &b);
printf("执行 swap_2 函数, a = %d, b = %d \n", a, b);
执行结果 :
[root@ip28 pointer]# gcc swap.c
[root@ip28 pointer]# ./a.out
初始值 : a = 10, b = 5
swap_1 传值 函数 a = 5, b = 10
执行 swap_1 函数, a = 10, b = 5
swap_2 传址 函数 a = 5, b = 10
执行 swap_2 函数, a = 5, b = 10
示例解析 :
– 传值调用 : swap_1 是传值调用, 传入的是 main 函数中的 a b 两个变量的副本, 因此函数执行完毕后, 主函数中的值是不变的;
– 传址调用 : swap_2 是传址调用, 传入的是 a , b 两个变量的地址 &a, &b, 当在swap_2 中进行修改的时候, 主函数中的 a,b变量也会发生改变;
(2) 高级示例
需求分析 : 调用getint()函数, 将输入的数字字符 转为一个整形数据;
getch 和 ungetch 函数 :
– 使用场景 : 当进行输入的时候, 不能确定是否已经输入足够的字符, 需要读取下一个字符, 进行判断, 如果多读取了一个字符, 就需要将这个字符退回去;
– 使用效果 : getch() 和 ungetch() 分别是预读下一个字符, 和 将预读的字符退回去, 这样对于其它代码而言, 没有任何影响;
注意的问题 : 出现问题, 暂时编译不通过, 找个C语言大神解决;
/*************************************************************************
& File Name: getint.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Mon 10 Mar :19 PM CST
************************************************************************/
#include &stdio.h&
#include &stdlib.h&
#include &ctype.h&
#define SIZE 5
int getint(int *p)
//sign 是用来控制数字的正负
//跳过空白字符, 如果是空白字符, 就会进行下一次循环, 直到不是空白字符为止
while(isspace(c = getc(stdin)));
//如果输入的字符不是数字, 就将预读的数据退回到标准输入流中
if(!isdigit(c) && c != EOF && c != '+' && c != '-')
ungetc(c, stdin);
* 如果预读的是减号, 那么sign 标识就是 -1,
* 如果预读的是加号, 那么sign 标识就是 1;
sign = (c == '-') ? -1 : 1;
//如果 c 是 加号 或者 减号, 再预读一个字符&
if(c == '+' || c == '-')
c = getc(stdin);
for(*p = 0; isdigit(c); c = getc(stdin))
*p = 10 * *p + (c - '0');
if(c != EOF)
ungetc(c, stdin);
int main(int argc, char **argv)
int n, array[SIZE],
for(n = 0; n & SIZE && getint(&array[n]) != EOF; n++);
for(i = 0; i & SIZE; i++)
printf("array[%d] = %d \n", i, array[i]);
执行结果 :
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out
array[0] = 123
array[1] = 123
array[2] = 43
array[3] = 674
array[4] = 1
5. 指针 和 数组
指针数组比较 :
– 可互相替代 : 数组下标执行的操作都可以使用指针替代;
– 效率比较 : 使用指针操作效率比数组要高;
指针 与 数组初始化 :
– 声明数组 : int a[10]; 定义一个长度为10 的int数组;
– 声明指针 : int *p; 定义一个指针, 该指针指向整型;
– 相互赋值 : p = &a[0], 将数组第一个元素的地址赋值给指针变量;
– 使用指针获取数组对象 : *p 等价于 a[0], *(p + 1) 等价于 a[1], *(p + i)等价于 a[i];
– 注意地址的运算 : p + i , 在地址运算上, 每次增加 sizeof(int) * i 个字节;
将数组赋值给指针的途径 :
– 将数组第一个元素地址赋值给指针变量 : p = &a[0];
– 将数组地址赋值给指针变量 : p =
指针 和 数组 访问方式互换 : 前提 int *p, a[10]; p =
– 数组计算方式 : 计算a[i]的时候, 先将数组转化为 *(a + i)指针, 然后计算该指针值;
– 取值等价 : a[i] 等价于 *(p + i);
– 地址等价 : &a[i] 与 a + i 是等价的;
– 指针下标访问 : p[i] 等价于 *(p + i);
– 结论 : 通过数组和下标 实现的操作 都可以使用 指针和偏移量进行等价替换;
指针 和 数组 的不同点 :
– 指针是变量 : int *p, a[10]; p = a 和 p++ 没有错误;
– 数组名不是变量 : int *p, a[10]; a = p 和 a++ 会报错;
数组参数 :
– 形参指针 : 将数组传作为参数传递给函数的时候, 传递的是数组的首地址, 传递地址, 形参是指针;
数组参数示例 :
– 函数参数是数组 : 函数传入一个字符串数组参数, 返回这个字符串长度;
/*************************************************************************
& File Name: array_param.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Sat 15 Mar :57 AM CST
************************************************************************/
#include&stdio.h&
//计算字符串长度
int strlen(char *s)
for(n = 0; *s != '\0'; s++)
int main(int argc, char** argv)
printf("strlen(djdhaj) = %d \n", strlen("djdhaj"));
printf("strlen(12) = %d \n", strlen("12"));
printf("strlen(dfe) = %d \n", strlen("dfe"));
– 执行结果 : warning: conflicting types for built-in function ‘strlen’, 原因是 C语言中已经有了 strlen 函数了, 如果改一个函数名, 就不会有这个警告了;
[root@ip28 pointer]# gcc array_param.c
array_param.c:12: warning: conflicting types for built-in function ‘strlen’
[root@ip28 pointer]# ./a.out
strlen(djdhaj) = 6
strlen(12) = 2
strlen(dfe) = 3
数组和指针参数 : 将数组名传给参数, 函数根据情况判断是作为数组还是作为指针;
– 实参 : 指针偏移量 和 数组下标 都可以作为 数组或指针函数形参, 如 数组情况fun(&array[2]) 或者 指针情况fun(p + 2);
– 形参 : 函数的形参可以声明为 fun(int array[]), 或者 fun(int *array), 如果传入的是数组的第二个元素的地址, 可以使用array[-2]来获数组取第一个元素;
数组指针参数示例 :
/*************************************************************************
& File Name: param_array_pointer.c
& Author: octopus
& Mail: octopus_work.163.com
& Created Time: Sat 15 Mar :33 AM CST
************************************************************************/
#include&stdio.h&
//使用指针做形参 取指针的前两位 和 当前位
void fun_p(int *p)
printf("*(p - 2) = %d \n", *(p - 2));
printf("*p = %d \n", *p);
//使用数组做形参 取数组的 第-2个元素 和 第0个元素
void fun_a(int p[])
printf("p[-2] = %d \n", p[-2]);
printf("p[0] = %d \n", p[0]);
int main(int argc, char **argv)
int array[] = {1,2,3,4,5};
//向指针参数函数中传入指针
printf("fun_p(array + 2) : \n");
fun_p(array + 2);
//向数组参数函数中传入数组元素地址
printf("fun_a(&array[2]) : \n");
fun_a(&array[2]);
//向指针参数函数中传入数组元素地址
printf("fun_p(&array[2]) : \n");
fun_p(&array[2]);
//向数组参数函数中传入指针
printf("fun_a(array + 2) : \n");
fun_a(array + 2);
执行效果 :
[root@ip28 pointer]# gcc param_array_pointer.c
[root@ip28 pointer]# ./a.out
fun_p(array + 2) :
*(p - 2) = 1
fun_a(&array[2]) :
fun_p(&array[2]) :
*(p - 2) = 1
fun_a(array + 2) :
作者 : 万境绝尘
C语言 内存分配 地址 指针 数组 参数 实例解析

我要回帖

更多关于 php 函数的传址调用 的文章

 

随机推荐