分类: C/C++
2013-05-07 14:55:40
转载自百度文库:
最近工作之余,发现了两个自己在C语言学习中的难点,一个是字符串指针和字符数组的区别,一个就是静态全局变量、静态局部变量、全局变量和局部变量的区别,在网上查了不少资料,收获良多,现在与大家分享,有错误的地方请大家指正!
以下程序用VC++6.0调试
先说说字符串指针和字符数组的区别
1. 相同点:
/* 用字符数组实现字符串操作 */
main( )
{
char str[]="Welcome to study C !";
int i;
printf("%s\n",str);
for (i=0;i<=7;i++)
printf("%c",str[i]); //用*(str+i)也行
printf("\n");
}
/* 用字符指针实现字符串操作 */
main()
{
char *str="Welcome to study C !";
int i;
printf("%s\n",str);
for(i=0;i<=7;i++)
printf("%c",*(str+i)); //用str[i]也行
printf("\n");
}
2. 不同点:
a) 赋值方式不同,字符数组只能对各个元素分别赋值,而字符指针只需赋给字符串的首地址就可以了。
如: char *str;
str="Welcome to study C !";
以下对字符数组的赋值是错误的:
char str[80];
str[ ]="Welcome to study C !";
b) 字符指针指向字符串,"hello"是一个字符串常量,与之相关联的内存空间位于内存的只读部分,如:
char ch[] = "china\n";
char *p;
char *pp = "CHINA\n";
p = ch;
*(p+2) = 'h';//就是可以的
*(pp+2) = 'h';//此处在编译时不会出错,在执行的时候会出错
c) 函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通的指针类型,对于void func (char sa[100],int ia[20],char *p),则sa的类型为char*,而不是char[100]类型
下面介绍一下字符串常量和字符串变量:
1. 字符串常量:
a) 定义:是一对双引号括起来的字符序列
b) 字符串包含的字符个数:不包括系统自动赋的’\0’,转义字符算1个
c) 所占的字节数:字符串所包含的字符个数加1
d) 长度:从第一个字符到第一个’\0’之间的字符个数,哪怕’\0’就在原字符串中
e) 无论字符串常量还是字符串变量,空字符串可以存在””,而空字符是错误的’’
2. 字符串变量:
a) C语言本身没有设置一种类型来定义字符串变量,字符串的存储完全依赖于字符数组,但字符数组又不等于是字符串变量,例如:
Char str[] = {‘a’,’b’,’c’,’\0’};是str[4],是字符串
Char str[] = {‘a’,’b’,’c’};是str[3],是字符数组
Char str[7] = “string!”;可能破坏其他数据
b) 在scanf,printf,gets,puts中的str不用写成str[10],只能写成str
下面介绍下静态全局变量,静态局部变量,全局变量,局部变量的区别
1. 从作用域看:全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用 extern 关键字再次声明这个全局变量。
2. 静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
3. 静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被 static 关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。
4. 从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。(扩展内存分配)
5. 把局部变量改变为静态变量后是改变了它的存储方式即增加了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
程序的内存分配
1. 程序占用的内存分为以下几个部分
a) 栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
b) 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
c) 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放。
d) 文字常量区:常量字符串就是放在这里的。 程序结束后由系统释放
e) 程序代码区:存放函数体的二进制代码。
2. 例子程序
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"
优化成一个地方。
}
因此 static 这个说明符在不同的地方所起的作用是不同的。
若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用 static 变量(这样的函数被称为:带“内部存储器”功能的的函数)
函数中必须要使用static 变量情况:比如当某函数的返回值为指针类型时,则必须是static 的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
static 全局变量:改变作用范围,不改变存储位置;static 局部变量:改变存储位置,不改变作用范围;静态函数 :在函数的返回类型前加上static 关键字,函数即被定义为静态函数,只能在声明它的文件当中可见,不能被其它文件使用。
初始化
如果括号中提供的处置个数大于数组长度,则会出错。如果初值小于数组长度,则将字符赋值给数组中前面的对应元素,其余元素自动填充空字符‘\0’。
格式化输出字符串时,输出项是字符数组名,不能写成数组中的元素。
输入函数的输入项直接写数组名,不写地址符&。
输入函数遇到空格认为结束。
两个字符数组变量不能直接赋值,只能通过移动下标操作字符数组中的每个元素进行分别赋值;两个字符值指针,可以直接赋值,即把一个字符指针所指向的地址赋值给另一个指针,则两个指针指向的同一个地址。字符数组和字符串两者之间不能直接赋值。
严格的说两个表达的意思是不完全一样的,因为前者是个字符串指针,这个指针S1所存的地址就是存储字符串前8个字节即hello/n/n/n的那个地址。
而后者是字符数组。每个字符都有一个独立的地址。
见图示。
字符串变量:在c中是没有这个概念的,c中如果想将一个字符串存放到变量中,必须使用字符数组,就是用一个字符型数组存放一个字符串,一些自己的保护代码,通过软件手段将这段内存软保护起来。这种保护在汇编级别可以轻松突破,其保护也就无效了。