5
21
2014
1

C/C++中堆、栈、自由存储区、全局/静态存储区、常量存储区

本文的内容来自

http://www.cnblogs.com/hanyonglu/archive/2011/04/12/2014212.html

 

在C/C++中,内存分为5个区,分别是堆、栈、自由存储区、全局/静态存区、常量存储区。

栈:由编译器在需要的时候分配,不需要时自动清除的存储区。里面的变量为局部变量、函数参数等。

堆:由new分配的内存块,释放是程序员代码手动的。delete来释放new的东西

自由存储区:malloc分配的内存块,和堆类似,不同处在于用free结束生命

全局/静态存储区:全局变量和静态变量。内存在程序编译的时候就已经分配好,这块内存在整个程序运行的期间都在

常量存储区:里面存放常量

以下看一个例子:

void f(){ int *p = new int[5];}

上面这个语句就调用了栈和堆,new 对应的为堆中分配的空间、指针p为栈中的存储区间。


下面重点讨论一下栈和堆的区别。

管理方式--栈:编译器自动管理,无需手动控制;堆:释放工作手动

空间大小--栈:默认大小较小,大小约为1M ;堆:32为系统,内存可达到4G。

碎片问题--栈,先进后出,不存在空间碎片;堆:频繁的new/delete会造成内存空间不连续

生长方向--栈,向内存地址小的方向增长;堆:向内存地址大的方向增长

分配方式--栈:静态和动态分配,静态分配编译器完成:如局部变量的分配。动态分配,如alloc函数,但其由编译器自动释放;堆:只能动态分配,new 需要手动释放。

分配效率--栈:机器系统提供的数据结构,计算机在底层对栈提供支持,效率高;堆:库函数提供,故机制较为复杂,效率偏低。

 

Category: 编程理解 | Tags:
5
11
2014
0

C/C++中函数、变量为何使用static

在C语言中,即非面向对象,与如下三点好处

1.用static修饰某个函数、变量,可以不用担心和别文件中的函数、变量重名问题。因为未加static则默认全局可见,这一功能就可以称为隐藏功能(函数唯一好处;非函数还可见2、3点)。

2.在运行过程中保持值不变。存储在静态数据区的变量只会在函数开始时初始化一次。有两种变量存储在静态数据区,一种是全局变量,另一种就是static。两者区别,全局变量全局可见、static隐藏了可见性,即该文件可见。看如下代码

#include <stdio.h>

int fun(void){
    static int count = 10;    // 函数初始化时赋值
    return count--;
}

int count = 1;

int main(void)
{    
    printf("global\t\tlocal static\n");
    for(; count <= 10; ++count)
        printf("%d\t\t%d\n", count, fun());    
    
    return 0;
}

运行结果如下

global          local static

1               10

2               9

3               8

4               7

5               6

6               5

7               4

8               3

9               2

10              1

3.自动初始化。数值类型自动初始化为0,static char *a[]初始化为一个串尾符。

#include <stdio.h>

int a;

int main(void)
{
    int i;
    static char str[10];

    printf("integer: %d;  string: (begin)%s(end)", a, str);

    return 0;
}

结果为integer: 0; string: (begin)(end)

 

若为面向对象,则:

1.在类中的static成员变量意味着被类的所有实例共享,即某个实例修改了改对象,则该修改对其他所有实例可见。

2.类中的static成员函数无this指针,故只能访问static成员变量。且还可以退出通过类名就可以访问成员和函数

3.指向static成员指针和指向static函数指针都是普通指针,即存放的是绝对地址。这一点同全局变量和全局函数,因为其特点差不多,但是类中的普通函数指针和普通成员指针是相对地址,即相对于这个类起始地址的偏移值,如下原因:1类的成员函数需要通过一个对象来调用

4.由于长期占有存储空间,故局部类不能定义静态数据成员,因为局部类的生存期和局部静态成员的生存期矛盾

5.union数据成员共享空间,而静态数据成员占有各自独立的存储单元。故union{static int a;static int b}错误

6.注意static修饰类的成员函数时不能与friend同时使用,因为friend是友元,而非自己的成员函数

参考:

http://blog.163.com/sunshine_linting/blog/static/4489332320119785228616/

http://zhidao.baidu.com/link?url=8D2YngLhHg2k9Ma10tJgKK4KykkJWcrjuJWx-v2xjcZvVTFn9oNr08xcJOY8_P2WoQH3sB4gBxemHJboLVw0qK

Category: 编程理解 | Tags: static
5
9
2014
0

bitmap操作

一下代码实现了位图的基本操作

/*以addr指向位置为起始地址,第nr个bit位的操作
  内容来自于文件系统中内核源码。bitmap.h
*/


//返回1,则该bit位为1
static  int happyhut_test_bit(unsigned int nr,char * addr) 
{
   //addr为char * 类型,一个char* 为8个bit,故addr[nr>>3],使其指向该nr对应的字节
   //(1<<(nr&7))确定该字节要test的bit位
  return (addr[nr >> 3] & (1<<((nr & 7)))) != 0;
}

static  int happyhut_set_bit(unsigned int nr,char * addr)
{
  int __res = happyhut_test_bit(nr,addr);
  addr[nr >> 3] |= (1<<((nr & 7)));//按位或,置1
  return __res != 0; \
}
//置0
static  int happyhut_clear_bit(unsigned int nr,char * addr)
{
  int __res = happyhut_test_bit(nr,addr);
  addr[nr >> 3] &= ~(1<<((nr & 7)));
  return __res != 0;
}
static int happyhut_test_and_clear_bit(unsigned int nr,char * addr)
{
	int __res = happyhut_test_bit(nr,addr);
	if(__res)//返回值为1,则该bit位为1
	happyhut_clear_bit(nr,addr);
	return __res;
}
static  int happyhut_test_and_set_bit(unsigned int nr,char * addr)
{
       int __res=happyhut_test_bit(nr,addr);
	 if(!__res)
	 happyhut_set_bit(nr,addr);
	 return __res;
	 	
}
//找第一个0的bit位
static int happyhut_find_first_zero_bit(char *addr,unsigned int size)
{
 unsigned int index;
 for(index=0;index<size;index++)
	 if(!happyhut_test_bit(index,addr))
		 return index;
 return index;
}

下面看图,帮助理解。addr指向一个char,char占8个字节

 

Category: 编程理解 | Tags:
5
6
2014
0

sizeof函数

sizeof函数返回时所占的字节个数。同一段代码在32位机器和64位机器上的sizeof返回值可能不同。代码如下

#include"stdio.h"
struct{}str;
struct{int a;}str1;

void main(int argc,char *argv)
{
	char *string="";
	char *s="1",*s1="123456789012345",a[3]="1";	
	int i,j1,j,k,k1,k2;
	i=sizeof(string);
	j=sizeof(s);
	j1=sizeof(s1);
	k=sizeof(a);
	k1=sizeof(str);
	k2=sizeof(str1);
	printf("%d  %d  %d  %d  %d  %d\n",i,j,j1,k,k1,k2);
}

在32位机器和64位机器的运行结果如截图。注意该结果是gcc 编译c的规则的结果

 

有如下几点总结:

1.在gcc编译器下编译c,struct中间是空,则sizeof返回0。这点与下面g++编译器对比

2.char *s="124342";sizeof(s);大小与s中的内容多少无关系。都是分配了一个固定大小,即指针所占的字节数。

 

再看下面代码:gcc编译

#include"stdio.h"
struct{}str1;
struct{int a;}str2;

int main(int argc,char *argv)
{
	char *s1="";
	char *s2="1",*s3="123456789012345",s4[3]="1",s5[]="123456789";	
	int i,i1,j1,j2,j3,j4,j5,j,k,k1,k2,k3;
	i=sizeof(s1);
	j=sizeof(s2);
	j1=sizeof(s3);
	k=sizeof(s4);
	k3=sizeof(s5);//
	k1=sizeof(str1);
	k2=sizeof(str2);
	i1=sizeof(*s1);//s1为char * 类型,*s1其实就是去其指向的char,故sizeof=1,一个字节
	j2=sizeof(*s2);
	j3=sizeof(*s3);
	j4=sizeof(*s4);
	j5=sizeof(*s5);//s5为指向"123456789"中的1的指针,故sizeof结果为1字节
	printf("s1=%d  s2=%d  s3=%d  s4=%d  s5=%d  str1=%d  str2=%d\n",i,j,j1,k,k3,k1,k2);
	printf("s_1=%d  s_2=%d  s_3=%d  s_4=%d  s_5=%d\n",i1,j2,j3,j4,j5);
	return 1;
}

运行结果如下。

我们可以看出结果在注释中

 


再看如下一段cpp代码:该段代码g++编译cpp类型

#include"stdio.h"
#include <iostream>
using namespace std;
struct circle0
{	
}cir0;
struct circle1
{
	int radius;
}cir1;
struct circle2
{
	int radius;
	circle2() {radius=1.0;}
}cir2;
struct circle3
{
	int radius;
	circle3() {radius=1.0;}
	~circle3(){radius=0;}
}cir3;
struct circle4
{
	int radius;
	circle4() {radius=1.0;}
	virtual ~circle4(){radius=0;}
}cir4;
struct circle5
{
	int radius;
	circle5() {radius=1.0;}
	virtual void f1(){cout<<"f1()\n";}
	virtual ~circle5(){radius=0;}
}cir5;
struct circle6
{
	int radius;
	circle6() {radius=1.0;}
	virtual void f1(){cout<<"f1()\n";}
	virtual ~circle6(){radius=0;}
	void f2() {cout<<"f2()\n";}
}cir6;
int main()
{
	int c0,c1,c2,c3,c4,c5,c6,c_0,c_1,c_2,c_3,c_4,c_5,c_6;
	c0=sizeof(cir0);
	c1=sizeof(cir1);
	c2=sizeof(cir2);
	c3=sizeof(cir3);
	c4=sizeof(cir4);
	c5=sizeof(cir5);
	c6=sizeof(cir6);
	c_0=sizeof(circle0);
	c_1=sizeof(circle1);
	c_2=sizeof(circle2);
	c_3=sizeof(circle3);
	c_4=sizeof(circle4);
	c_5=sizeof(circle5);
	c_6=sizeof(circle6);
	printf("c0:%d  c1:%d  c2:%d  c3:%d  c4:%d  c5:%d   c6:%d\n",c0,c1,c2,c3,c4,c5,c5);
	printf("c_0:%d c_1:%d c_2:%d c_3:%d c_4:%d c_5:%d c_6:%d\n",c_0,c_1,c_2,c_3,c_4,c_5,c_6);
	
	return 1;
}

运行结果

我们可以得出如下结论

1.c编译时struct的结构如果为空,则sizeof(struct)结果为0;而c++编译则不然,结果为1

2.构造函数、析构函数、非virtual函数不占struct的空间,因为调用函数只需要知道函数的地址,而函数的地址只与类型有关,而与类型的实例无关,编译器不会因为函数而在实例中添加额外信息

3.struct中若有virtual声明的函数,则多一个指针类型的空间。因为若有虚函数,则会为该类型添加一个虚类型的表,该实例就会有一个指向虚类型的指针。故多一个指针的空间。故一个virtual函数和两个virtual函数实际上都只是多一个指针类型。

 

 


Category: 编程理解 | Tags:
4
22
2014
0

关于char *用法

关于一下

char * pChar;

if(NULL==(pChar=(char *)malloc(siziof(char)*200)))printf("malloc error\n")

memset((void*)pChar,0,200);//把200个字节内容清零

print("pChar[0]=%c",pChar[0]);

i=(pChar[0]==0;)printf("~~~%ld\n",i);

pChar[0]=1;

print("pChar[0]=%c",pChar[0]);

i=(pChar[0]==0;)printf("~~~%ld\n",i);

pChar[0]=48;

print("pChar[0]=%c",pChar[0]);

i=(pChar[0]==0;)printf("~~~%ld\n",i);

其实*pChar的内容置0,其实就是置为串尾符。

执行结果是:

由上面的结果也可以看出pChar=0其实是赋值NULL。清空

pChar=0,或者pChar=1,进行时直接的acsii值表的赋值。直接查国际Ascii表就可以知道结果了。比如数字0对应的ascii表值为48,则:

print("pChar[0]=%c",pChar[0]);的结果和ASCII码表相对应。故pChar[0]=48;则print("pChar[0]=%c",pChar[0]);打印的结果pChar[0]=0

 

 

故可以有如下操作

...

i=**;

if(pChar[i]==0)pChar[i]=1;

...

即虽然pChar[i]为char类型,但是可以直接赋值0,1.即按照ACSII码表来赋值

Category: 编程理解 | Tags:

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com