作用域与函数传值调用
2014-10-18 17:22
190 查看
作用域与函数传值调用 - tanglinux - 博客频道 - CSDN.NET
http://blog.csdn.net/npy_lp/article/details/6925878
在C语言中,所有变量、宏、函数(函数的声明形式即为函数原型)、自定义数据类型以及别名等数据必须先声明后使用。通常在头文件中包含这些声明,如extern int global_data,这个声明只是告诉编译器全局变量的类型和名字,至于对它的定义(分配内存的声明即为定义)则在别处进行。
1、作用域
在C语言中,常见的有代码块(一对花括号之间的代码)作用域和文件作用域。
所有函数之外定义的变量叫作全局变量(也叫外部变量,默认具有静态存储特性)。某个代码块之内定义的变量(包括函数定义中的参数)就是局部变量(默认具有动态存储特性,使用static修饰会使用局部变量具有静态特性)。局部变量只具有空链接特性,即只能在定义它的代码块中被访问。
文件作用域是对全局变量和函数而言的。默认都具有外部链接性(即可以被多文件程序的其他文件中的数据所访问),加static修饰时只具有内部链接性(也就是说只能被本文件的数据所访问)。
知识点:
(1)、具有静态存储期的变量在程序执行过程中一直存在。而具有动态存储期的变量只有在执行到这些变量所属的代码块时才为其分配内存,并且在退出此代码块时,就释放掉所分配的内存。
举例,如清单1:
[cpp] view
plaincopy
#include <stdio.h>
char *func(void)
{
char a[] = "hello world";
return a;
}
int main(void)
{
char *p = NULL;
p = func();
printf("%s\n", p);
return 0;
}
用GCC编译时,会警告说函数不能返回局部变量的地址。程序执行时,不能正确输出数组a中的字符,只是一些乱码,那是因为在第14行的函数调用之后,数组a就已经被释放掉了。
注意:指针变量p可以获得函数func返回的数组a的首地址,但数组a中的值在调用之后就已经不存在了。
(2)、在程序员未明确赋初始值的情况下,编译器自动把静态变量(即具有静态存储期的变量,包括全局变量和用static修饰的局部变量)初始化为0或NULL(这个值是针对指针变量而言的),而动态变量(即具有动态存储期的变量)的初始值是不确定的。
2、传值调用
由于函数中的数据只为本函数所有,所以在C语言中,函数之间交往数据的通路只有两种:全局变量和传值调用。
普通变量的传值调用,如清单2:
[cpp] view
plaincopy
#include <stdio.h>
void func(int a, int b)
{
printf("in func, address a = %p, b = %p\n", &a, &b);
printf("in func, value a = %d, b = %d\n", a, b);
}
int main(void)
{
int a = 3, b = 4;
func(a, b);
printf("in main, address a = %p, b = %p\n", &a, &b);
printf("in main, value a = %d, b = %d\n", a, b);
return 0;
}
例子输出结果:
[cpp] view
plaincopy
in func, address a = 0xbf8cc770, b = 0xbf8cc774
in func, value a = 3, b = 4
in main, address a = 0xbf8cc78c, b = 0xbf8cc788
in main, value a = 3, b = 4
在main函数中,通过函数传值调用(例子中的第14行)把变量a和b的值传给func函数中的a和b(整个传值过程就相当于赋值)。注意,这两个函数中的变量a和b虽然同名,但互不影响,属于不同的变量,从结果中它们的地址就可知。
与指针变量有关的传值调用,如清单3:
[cpp] view
plaincopy
#include <stdio.h>
void func(int *p1, int *p2)
{
*p1 += 5;
*p2 += 5;
}
int main(void)
{
int a = 3, b = 4;
printf("before calling, a = %d, b = %d\n", a, b);
func(&a, &b);
printf("after calling, a = %d, b = %d\n", a, b);
return 0;
}
例子输出结果:
[cpp] view
plaincopy
before calling, a = 3, b = 4
after calling, a = 8, b = 9
在main函数中,把变量a和b的地址(也是一个数值)传给func函数中的指针变量p1和p2,然后通过间接运算符来改变a和b的值。
相对复杂的例子,如清单4:
[cpp] view
plaincopy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(char *p)
{
p = (char *)malloc(20);
}
int main(void)
{
char *str = NULL;
func(str);
strcpy(str, "hello world");
printf("string is %s\n", str);
return 0;
}
在例子中,通过函数调用,把指针变量str的值NULL传递给func函数的指针变量p,而后p的值又被malloc函数返回的地址所覆盖,其实例子中的函数调用对str值的改变没有任何影响,一直都是NULL,而往NULL中拷贝数据会产生段错误。
注意,用函数malloc分配的内存必须通过free函数来释放,否则在程序执行过程中,所分配的内存一直被占用。
http://blog.csdn.net/npy_lp/article/details/6925878
在C语言中,所有变量、宏、函数(函数的声明形式即为函数原型)、自定义数据类型以及别名等数据必须先声明后使用。通常在头文件中包含这些声明,如extern int global_data,这个声明只是告诉编译器全局变量的类型和名字,至于对它的定义(分配内存的声明即为定义)则在别处进行。
1、作用域
在C语言中,常见的有代码块(一对花括号之间的代码)作用域和文件作用域。
所有函数之外定义的变量叫作全局变量(也叫外部变量,默认具有静态存储特性)。某个代码块之内定义的变量(包括函数定义中的参数)就是局部变量(默认具有动态存储特性,使用static修饰会使用局部变量具有静态特性)。局部变量只具有空链接特性,即只能在定义它的代码块中被访问。
文件作用域是对全局变量和函数而言的。默认都具有外部链接性(即可以被多文件程序的其他文件中的数据所访问),加static修饰时只具有内部链接性(也就是说只能被本文件的数据所访问)。
知识点:
(1)、具有静态存储期的变量在程序执行过程中一直存在。而具有动态存储期的变量只有在执行到这些变量所属的代码块时才为其分配内存,并且在退出此代码块时,就释放掉所分配的内存。
举例,如清单1:
[cpp] view
plaincopy
#include <stdio.h>
char *func(void)
{
char a[] = "hello world";
return a;
}
int main(void)
{
char *p = NULL;
p = func();
printf("%s\n", p);
return 0;
}
用GCC编译时,会警告说函数不能返回局部变量的地址。程序执行时,不能正确输出数组a中的字符,只是一些乱码,那是因为在第14行的函数调用之后,数组a就已经被释放掉了。
注意:指针变量p可以获得函数func返回的数组a的首地址,但数组a中的值在调用之后就已经不存在了。
(2)、在程序员未明确赋初始值的情况下,编译器自动把静态变量(即具有静态存储期的变量,包括全局变量和用static修饰的局部变量)初始化为0或NULL(这个值是针对指针变量而言的),而动态变量(即具有动态存储期的变量)的初始值是不确定的。
2、传值调用
由于函数中的数据只为本函数所有,所以在C语言中,函数之间交往数据的通路只有两种:全局变量和传值调用。
普通变量的传值调用,如清单2:
[cpp] view
plaincopy
#include <stdio.h>
void func(int a, int b)
{
printf("in func, address a = %p, b = %p\n", &a, &b);
printf("in func, value a = %d, b = %d\n", a, b);
}
int main(void)
{
int a = 3, b = 4;
func(a, b);
printf("in main, address a = %p, b = %p\n", &a, &b);
printf("in main, value a = %d, b = %d\n", a, b);
return 0;
}
例子输出结果:
[cpp] view
plaincopy
in func, address a = 0xbf8cc770, b = 0xbf8cc774
in func, value a = 3, b = 4
in main, address a = 0xbf8cc78c, b = 0xbf8cc788
in main, value a = 3, b = 4
在main函数中,通过函数传值调用(例子中的第14行)把变量a和b的值传给func函数中的a和b(整个传值过程就相当于赋值)。注意,这两个函数中的变量a和b虽然同名,但互不影响,属于不同的变量,从结果中它们的地址就可知。
与指针变量有关的传值调用,如清单3:
[cpp] view
plaincopy
#include <stdio.h>
void func(int *p1, int *p2)
{
*p1 += 5;
*p2 += 5;
}
int main(void)
{
int a = 3, b = 4;
printf("before calling, a = %d, b = %d\n", a, b);
func(&a, &b);
printf("after calling, a = %d, b = %d\n", a, b);
return 0;
}
例子输出结果:
[cpp] view
plaincopy
before calling, a = 3, b = 4
after calling, a = 8, b = 9
在main函数中,把变量a和b的地址(也是一个数值)传给func函数中的指针变量p1和p2,然后通过间接运算符来改变a和b的值。
相对复杂的例子,如清单4:
[cpp] view
plaincopy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(char *p)
{
p = (char *)malloc(20);
}
int main(void)
{
char *str = NULL;
func(str);
strcpy(str, "hello world");
printf("string is %s\n", str);
return 0;
}
在例子中,通过函数调用,把指针变量str的值NULL传递给func函数的指针变量p,而后p的值又被malloc函数返回的地址所覆盖,其实例子中的函数调用对str值的改变没有任何影响,一直都是NULL,而往NULL中拷贝数据会产生段错误。
注意,用函数malloc分配的内存必须通过free函数来释放,否则在程序执行过程中,所分配的内存一直被占用。
相关文章推荐
- 作用域与函数传值调用
- 作用域与函数传值调用
- 关于,函数调用是传值调用,初始化函数中重新分配内存,导致形参的值和实参的值不一致 问题分析
- 子窗体如何传值到父窗体并调用父窗体的函数
- Scala从零开始:函数参数的传名调用(call-by-name)和传值调用(call-by-value)
- C++ primer 这本书上有这么两句话“派生类虚函数调用基类版本时,必须显式使用作用域操作符。如果派生类函数忽略了这样做,则函数调用会在运行时确定并且将是一个自身调用,从而导致无穷递归。”
- Iframe之间以及父窗体的函数调用、传值
- 关于栈在函数调用中的作用
- js使用立即调用的函数表达式创建局部作用域问题
- 实例讲解iframe之间以及父窗体的函数调用传值
- 函数调用和inline作用
- javaGUI编程中JFrame对象调用的add()函数的作用及来源
- C语言的函数传值调用(24)
- 函数里面有函数叫函数的闭包:子函数可以调用父函数变量,如果子函数找不到变量,那么整条作用域链的变量都会被保存
- [Effective JavaScript 笔记] 第13条:使用立即调用的函数表达式创建局部作用域
- inherited在消息中的作用(编译器根据inherited所在的函数,直接转换成对祖先类同名动态函数的调用,或者转换成对DefaultHandler的调用)
- c#中函数调用的按值传递和按引用传值
- 子窗体如何传值到父窗体并调用父窗体的函数
- C语言函数调用时参数压栈的顺序以及函数指针的作用
- 函数 传值调用 指针调用 引用调用