分类目录归档:C++基础

主要用于C++语言相关的基础知识

indent 命令

indent 命令

功能说明:调整C原始代码文件的格式。 

语  法:indent [参数][源文件] 或 indent [参数][源文件][-o 目标文件]
补充说明:indent可辨识C的原始代码文件,并加以格式化,以方便程序设计师阅读。
参  数:
-bad或--blank-lines-after-declarations   在声明区段或加上空白行。 
-bap或--blank-lines-after-procedures  在程序或加上空白行。 
-bbb或--blank-lines-after-block-comments  在注释区段后加上空白行。 
-bc或--blank-lines-after-commas   在声明区段中,若出现逗号即换行。 
-bl或--braces-after-if-line  if(或是else,for等等)与后面执行区段的""自成一行。 
-bli<缩排格数>或--brace-indent<缩排格数>  设置缩排的格数。 
-br或--braces-on-if-line  if(或是else,for等等)与后面执行跛段的""自成一行。 
-bs或--blank-before-sizeof  在sizeof之后空一格。 
-c<栏数>或--comment-indentation<栏数>  将注释置于程序码右侧指定的栏位。 
-cd<栏数>或--declaration-comment-column<栏数>  将注释置于声明右侧指定的栏位。 
-cdb或--comment-delimiters-on-blank-lines  注释符号自成一行。 
-ce或--cuddle-else  将else置于"}"(if执行区段的结尾)之后。 
-ci<缩排格数>或--continuation-indentation<缩排格数>  叙述过长而换行时,指定换行后缩排的格数。 
-cli<缩排格数>或--case-indentation-<缩排格数>  使用case时,switch缩排的格数。 
-cp<栏数>或-else-endif-column<栏数>  将注释置于else与elseif叙述右侧定的栏位。 
-cs或--space-after-cast  在cast之后空一格。 
-d<缩排格数>或-line-comments-indentation<缩排格数>  针对不是放在程序码右侧的注释,设置其缩排格数。 
-di<栏数>或--declaration-indentation<栏数>  将声明区段的变量置于指定的栏位。 
-fc1或--format-first-column-comments  针对放在每行最前端的注释,设置其格式。 
-fca或--format-all-comments  设置所有注释的格式。 
-gnu或--gnu-style  指定使用GNU的格式,此为预设值。 
-i<格数>或--indent-level<格数>  设置缩排的格数。 
-ip<格数>或--parameter-indentation<格数>  设置参数的缩排格数。 
-kr或--k-and-r-style  指定使用Kernighan&Ritchie的格式。 
-lp或--continue-at-parentheses  叙述过长而换行,且叙述中包含了括弧时,将括弧中的每行起始栏位内容垂直对其排列。 
-nbad或--no-blank-lines-after-declarations  在声明区段后不要加上空白行。 
-nbap或--no-blank-lines-after-procedures  在程序后不要加上空白行。 
-nbbb或--no-blank-lines-after-block-comments  在注释区段后不要加上空白行。 
-nbc或--no-blank-lines-after-commas  在声明区段中,即使出现逗号,仍旧不要换行。 
-ncdb或--no-comment-delimiters-on-blank-lines  注释符号不要自成一行。 
-nce或--dont-cuddle-else  不要将else置于"}"之后。 
-ncs或--no-space-after-casts  不要在cast之后空一格。 
-nfc1或--dont-format-first-column-comments  不要格式化放在每行最前端的注释。 
-nfca或--dont-format-comments  不要格式化任何的注释。 
-nip或--no-parameter-indentation  参数不要缩排。 
-nlp或--dont-line-up-parentheses  叙述过长而换行,且叙述中包含了括弧时,不用将括弧中的每行起始栏位垂直对其排列。 
-npcs或--no-space-after-function-call-names  在调用的函数名称之后,不要加上空格。 
-npro或--ignore-profile  不要读取indent的配置文件.indent.pro。 
-npsl或--dont-break-procedure-type  程序类型与程序名称放在同一行。 
-nsc或--dont-star-comments  注解左侧不要加上星号(*)。 
-nsob或--leave-optional-semicolon  不用处理多余的空白行。 
-nss或--dont-space-special-semicolon   若for或while区段仅有一行时,在分号前不加上空格。 
-nv或--no-verbosity  不显示详细的信息。 
-orig或--original  使用Berkeley的格式。 
-pcs或--space-after-procedure-calls  在调用的函数名称与"{"之间加上空格。 
-psl或--procnames-start-lines  程序类型置于程序名称的前一行。 
-sc或--start-left-side-of-comments  在每行注释左侧加上星号(*)。 
-sob或--swallow-optional-blank-lines  删除多余的空白行。 
-ss或--space-special-semicolon  若for或swile区段今有一行时,在分号前加上空格。 
-st或--standard-output  将结果显示在标准输出设备。 
-T  数据类型名称缩排。 
-ts<格数>或--tab-size<格数>  设置tab的长度。 
-v或--verbose  执行时显示详细的信息。 
-version  显示版本信息。
例  子:
indent -kr -i8 -ts8 -sob -l80 -ss -bs -npsl <file>
indent  -kr -bap -nce -i8 -ts8 -sob -l80 -ss -bs -npsl -bl  -bli0 <file>
使用的indent参数 含义
--blank-lines-after-declarations bad 变量声明后加空行
--blank-lines-after-procedures bap 函数结束后加空行
--blank-lines-before-block-comments bbb 块注释前加空行
--break-before-boolean-operator bbo 较长的行,在逻辑运算符前分行
--blank-lines-after-commas nbc 变量声明中,逗号分隔的变量不分行
--braces-after-if-line bl "if"和"{"分做两行
--brace-indent 0 bli0 "{"不继续缩进
--braces-after-struct-decl-line bls 定义结构,"struct"和"{"分行
--comment-indentationn c33 语句后注释开始于行33
--declaration-comment-columnn cd33 变量声明后注释开始于行33
--comment-delimiters-on-blank-lines ncdb 不将单行注释变为块注释
--cuddle-do-while ncdw "do --- while"的"while"和其前面的"}"另起一行
--cuddle-else nce "else"和其前面的"}"另起一行
--case-indentation 0 cli0 switch中的case语句所进0个空格
--else-endif-columnn cp33 #else, #endif后面的注释开始于行33
--space-after-cast cs 在类型转换后面加空格
--line-comments-indentation n d0 单行注释(不从1列开始的),不向左缩进
--break-function-decl-args nbfda 关闭:函数的参数一个一行
--declaration-indentationn di2 变量声明,变量开始于2行,即不必对齐
--format-first-column-comments nfc1 不格式化起于第一行的注释
--format-all-comments nfca 不开启全部格式化注释的开关
--honour-newlines hnl Prefer to break long lines at the position of newlines in the input.
--indent-leveln i4 设置缩进多少字符,如果为tab的整数倍,用tab来缩进,否则用空格填充。
--parameter-indentationn ip5 旧风格的函数定义中参数说明缩进5个空格
--line-length 75 l75 非注释行最长75
--continue-at-parentheses lp 续行从上一行出现的括号开始
--space-after-procedure-calls pcs 函数和"("之间插入一个空格
--space-after-parentheses nprs 在"("后")"前不插入空格
--procnames-start-lines psl 将函数名和返回类型放在两行定义
--space-after-for saf for后面有空格
--space-after-if sai if后面有空格
--space-after-while saw while后面有空格
--start-left-side-of-comments nsc 不在生成的块注释中加*
--swallow-optional-blank-lines nsob 不去掉可添加的空行
--space-special-semicolon nss 一行的for或while语句,在";"前不加空。
--tab-size ts4 一个tab为4个空格(要能整除"-in")
--use-tabs ut 使用tab来缩进
如上参数可写入用户目录下的文件:”.indent.pro”,作为运行indent的缺省参数。

判断linux服务器的网络字节序

将低位字节存储在起始地址,称为小端(little-endian)字节序;将高位字节存储在起始地址,称为大端(big-endian)字节序
网络字节序是大端(big-endian)字节序

#include 
int main(int argc,char* argv[])
{
        union{
                short s;
                char c[sizeof(short)];
        }un;

        un.s    = 0x0102;

        if(sizeof(short)==2)
        {
                if(un.c[0]==1 && un.c[1]==2)
                        printf("big-endian\n");
                else if(un.c[0]==2 && un.c[1]==1)
                        printf("little-endian\n");
                else
                        printf("unknown\n");
        }
        else
                printf("sizeof(short) = %d\n",sizeof(short));

        return 0;
}

C语言中有关string的函数详解

@函数名称: strdup

函数原型: char *strdup(const char *s)
函数功能: 字符串拷贝,目的空间由该函数分配
函数返回: 指向拷贝后的字符串指针
参数说明: src-待拷贝的源字符串
所属文件:

#include 
#include 
#include 
int main()
{
	char *dup_str, *string="abcde";
	dup_str=strdup(string);
	printf("%s", dup_str);
	free(dup_str);
	return 0;
}

@函数名称: strcpy
函数原型: char* strcpy(char* str1,char* str2);
函数功能: 把str2指向的字符串拷贝到str1中去
函数返回: 返回str1,即指向str1的指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char string[10];
	char *str1="abcdefghi";
	strcpy(string,str1);
	printf("the string is:%s\n",string);
	return 0;
}

@函数名称: strncpy
函数原型: char *strncpy(char *dest, const char *src,int count)
函数功能: 将字符串src中的count个字符拷贝到字符串dest中去
函数返回: 指向dest的指针
参数说明: dest-目的字符串,src-源字符串,count-拷贝的字符个数
所属文件:

#include 
#include 
int main()
{
	char string[10];
	char *str1="abcdefghi";
	strncpy(string,str1,3);
	string[3]='\0';
	printf("%s",string);
	return 0;
}

@函数名称: strcat
函数原型: char* strcat(char * str1,char * str2);
函数功能: 把字符串str2接到str1后面,str1最后的’\0’被取消
函数返回: str1
参数说明:
所属文件:

#include 
#include 

int main()
{
	char buffer[80];
	
	strcpy(buffer,"Hello ");
	strcat(buffer,"world");
	printf("%s\n",buffer);
	return 0;
}

@函数名称: strncat
函数原型: char *strncat(char *dest, const char *src, size_t maxlen)
函数功能: 将字符串src中前maxlen个字符连接到dest中
函数返回:
参数说明:
所属文件:

#include 
#include 

char buffer[80];

int main()
{
	strcpy(buffer,"Hello ");
	strncat(buffer,"world",8);
	printf("%s\n",buffer);
	strncat(buffer,"*************",4);
	printf("%s\n",buffer);
	return 0;
}

@函数名称: strcmp
函数原型: int strcmp(char * str1,char * str2);
函数功能: 比较两个字符串str1,str2.
函数返回: str1str2,返回正数.
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *buf1="aaa", *buf2="bbb", *buf3="ccc";
	int ptr;
	ptr=strcmp(buf2, buf1);
	if(ptr>0)
		printf("buffer 2 is greater than buffer 1\n");
	else
		printf("buffer 2 is less than buffer 1\n");
	ptr=strcmp(buf2, buf3);
	if(ptr>0)
		printf("buffer 2 is greater than buffer 3\n");
	else
		printf("buffer 2 is less than buffer 3\n");

	return 0;
}

@函数名称: strncmp
函数原型: int strncmp(char *str1,char *str2,int count)
函数功能: 对str1和str2中的前count个字符按字典顺序比较
函数返回: 小于0:str1str2
参数说明: str1,str2-待比较的字符串,count-比较的长度
所属文件:

#include 
#include 
int main()
{
	int ptr; 
	char *buf1="aaabbb",*buf2="bbbccc",*buf3="ccc";
	ptr=strncmp(buf2,buf1,3);
	if (ptr>0)
		printf("buffer 2 is greater than buffer 1");
	else
		printf("buffer 2 is less than buffer 1");
	
	ptr=strncmp(buf2,buf3,3);
	if (ptr>0)
		printf("buffer 2 is greater than buffer 3");
	else
		printf("buffer 2 is less than buffer 3");
	return(0);
}

@函数名称: strpbrk
函数原型: char *strpbrk(const char *s1, const char *s2)
函数功能: 得到s1中第一个“同时也出现在s2中”字符的位置指针
函数返回: 位置指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *p="Find all vowels";
	
	while(p)
	{
		printf("%s\n",p);
	  p=strpbrk(p+1,"aeiouAEIOU");
	}
	return 0;
}

@函数名称: strcspn
函数原型: int strcspn(const char *s1, const char *s2)
函数功能: 统计s1中从头开始直到第一个“来自s2中的字符”出现的长度
函数返回: 长度
参数说明:
所属文件:

#include 
#include 

int main()
{
	printf("%d\n",strcspn("abcbcadef","cba"));
	printf("%d\n",strcspn("xxxbcadef","cba"));
	printf("%d\n",strcspn("123456789","cba"));
	return 0;
}

@函数名称: strspn
函数原型: int strspn(const char *s1, const char *s2)
函数功能: 统计s1中从头开始直到第一个“不来自s2中的字符”出现的长度
函数返回: 位置指针
参数说明:
所属文件:

#include 
#include 
#include 
int main()
{
	printf("%d\n",strspn("out to lunch","aeiou"));
	printf("%d\n",strspn("out to lunch","xyz"));
	return 0;
}

@函数名称: strchr
函数原型: char* strchr(char* str,char ch);
函数功能: 找出str指向的字符串中第一次出现字符ch的位置
函数返回: 返回指向该位置的指针,如找不到,则返回空指针
参数说明: str-待搜索的字符串,ch-查找的字符
所属文件:

#include 
#include 
int main()
{
	char string[15];
	char *ptr, c='r';
	strcpy(string, "This is a string");
	ptr=strchr(string, c);
	if (ptr)
	  printf("The character %c is at position: %d\n",c,ptr-string);
	else
	  printf("The character was not found\n");
	return 0;
}

@函数名称: strrchr
函数原型: char *strrchr(const char *s, int c)
函数功能: 得到字符串s中最后一个含有c字符的位置指针
函数返回: 位置指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char string[15];
	char *ptr,c='r';
	strcpy(string,"This is a string");
	ptr=strrchr(string,c);
	if (ptr)
	  printf("The character %c is at position:%d",c,ptr-string);
	else
	  printf("The character was not found");
	return 0;
}

@函数名称: strstr
函数原型: char* strstr(char* str1,char* str2);
函数功能: 找出str2字符串在str1字符串中第一次出现的位置(不包括str2的串结束符)
函数返回: 返回该位置的指针,如找不到,返回空指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *str1="Open Watcom C/C++",*str2="Watcom",*ptr;
	ptr=strstr(str1,str2);
	printf("The substring is:%s\n",ptr);
	return 0;
}

@函数名称: strrev
函数原型: char *strrev(char *s)
函数功能: 将字符串中的所有字符颠倒次序排列
函数返回: 指向s的指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *forward="string";
	printf("Before strrev():%s",forward);
	strrev(forward);
	printf("After strrev(): %s",forward);
	return 0;
}

@函数名称: strnset
函数原型: char *strnset(char *s, int ch, size_t n)
函数功能: 将字符串s中前n个字符设置为ch的值
函数返回: 指向s的指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *string="abcdefghijklmnopqrstuvwxyz";
	char letter='x';
	printf("string before strnset: %s",string);
	strnset(string,letter,13);
	printf("string after strnset: %s",string);
	return 0;
}

@函数名称: strset
函数原型: char *strset(char *s, int ch)
函数功能: 将字符串s中所有字符设置为ch的值
函数返回: 指向s的指针
参数说明:
所属文件:

#include 
#include 
int main()
{
	char string[10]="123456789";
	char symbol='c';
	printf("Before strset(): %s", string);
	strset(string, symbol);
	printf("After strset(): %s", string);
	return 0;
}

@函数名称: strtok
函数原型: char *strtok(char *s1, const char *s2)
函数功能: 分解s1字符串为用特定分隔符分隔的多个字符串(一般用于将英文句分解为单词)
函数返回: 字符串s1中首次出现s2中的字符前的子字符串指针
参数说明: s2一般设置为s1中的分隔字符
规定进行子调用时(即分割s1的第二、三及后续子串)第一参数必须是NULL
在每一次匹配成功后,将s1中分割出的子串位置替换为NULL(摘下链中第一个环),因此s1被破坏了
函数会记忆指针位置以供下一次调用

所属文件:

#include 
#include 
int main()
{
	char *p;
	char *buffer;
	char *delims={ " .," };
	
	buffer=strdup("Find words, all of them.");
	printf("%s\n",buffer);
	p=strtok(buffer,delims);
	while(p!=NULL){
		printf("word: %s\n",p);
		p=strtok(NULL,delims);
	}
	printf("%s\n",buffer);
	return 0;
}

@函数名称: strupr
函数原型: char *strupr(char *s)
函数功能: 将字符串s中的字符变为大写
函数返回:
参数说明:
所属文件:

#include 
#include 
int main()
{
	char *string="abcdefghijklmnopqrstuvwxyz",*ptr;
	ptr=strupr(string);
	printf("%s",ptr);
	return 0;
}

@函数名称: strlwr
函数原型: char *strlwr(char *s)
函数功能: 将字符串中的字符变为小写字符
函数返回: 指向s的指针
参数说明:
所属文件:

#include
int main()
{
	char str[]="HOW TO SAY?";
	printf("%s",strlwr(str));
	return 0;
}

@函数名称: strlen
函数原型: unsigned int strlen(char * str);
函数功能: 统计字符串str中字符的个数(不包括终止符’\0′)
函数返回: 返回字符串的长度.
参数说明:
所属文件:

#include 
#include
int main()
{
	char str[]="how are you!";
	printf("the lence is:%d\n",strlen(str));
	return 0;
}

@函数名称: strerror
函数原型: char *strerror(int errnum)
函数功能: 得到错误信息的内容信息
函数返回: 错误提示信息字符串指针
参数说明: errnum-错误编号
所属文件:

#include 
#include 
int main()
{
	char *buffer;
	buffer=strerror(errno);
	printf("Error: %s",buffer);
	return 0;
}

@函数名称: memcpy
函数原型: void *memcpy(void *dest, const void *src, size_t n)
函数功能: 字符串拷贝
函数返回: 指向dest的指针
参数说明: src-源字符串,n-拷贝的最大长度
所属文件: ,

#include 
#include 
int main()
{
	char src[]="******************************";
	char dest[]="abcdefghijlkmnopqrstuvwxyz0123456709";
	char *ptr;
	printf("destination before memcpy:%s\n",dest);
	ptr=memcpy(dest,src,strlen(src));
	if (ptr)
		printf("destination after memcpy:%s\n",dest);
	else
		printf("memcpy failed");
		
	return 0;
}

@函数名称: memccpy
函数原型: void *memccpy(void *dest, const void *src, int c, size_t n)
函数功能: 字符串拷贝,到指定长度或遇到指定字符时停止拷贝
函数返回:
参数说明: src-源字符串指针,c-中止拷贝检查字符,n-长度,dest-拷贝底目的字符串指针
所属文件: ,

#include 
#include 
int main()
{
	char *src="This is the source string";
	char dest[50];
	char *ptr;
	ptr=memccpy(dest,src,'c',strlen(src));
	if (ptr)
	{
		*ptr='\0';
		printf("The character was found:%s",dest);
	}
	else
		printf("The character wasn't found");
	return 0;
}

@函数名称: memchr
函数原型: void *memchr(const void *s, int c, size_t n)
函数功能: 在字符串中第开始n个字符中寻找某个字符c的位置
函数返回: 返回c的位置指针,返回NULL时表示未找到
参数说明: s-要搜索的字符串,c-要寻找的字符,n-指定长度
所属文件: ,

#include 
#include 
int main()
{
	char str[17];
	char *ptr;
	strcpy(str,"This is a string");
	ptr=memchr(str,'r',strlen(str));
	if (ptr)
		printf("The character 'r' is at position: %d",ptr-str);
	else
		printf("The character was not found");
		
	return 0;
}

@函数名称: memcmp
函数原型: int memcmp(const void *s1, const void *s2,size_t n)
函数功能: 按字典顺序比较两个串s1和s2的前n个字节
函数返回: <0,=0,>0分别表示s1<,=,>s2
参数说明: s1,s2-要比较的字符串,n-比较的长度
所属文件: ,

#include 
#include 
int main() 
{ 
	char *buf1="ABCDE123"; 
	char *buf2="abcde456"; 
	int stat; 
	stat=memcmp(buf1,buf2,5); 
	printf("The strings to position 5 are "); 
	if(stat) 
		printf("not "); 
	
	printf("the same\n"); 
	return 0; 
} 

@函数名称: memicmp
函数原型: int memicmp(const void *s1, const void *s2, size_t n)
函数功能: 按字典顺序、不考虑字母大小写对字符串s1,s2前n个字符比较
函数返回: <0,=0,>0分别表示s1<,=,>s2
参数说明: s1,s2-要比较的字符串,n-比较的长度
所属文件: ,

#include 
#include 
int main()
{
	char *buf1="ABCDE123";
	char *buf2="abcde456";
	int stat;
	stat=memicmp(buf1,buf2,5);
	printf("The strings to position 5 are ");
	if(stat) 
		printf("not");
	
	printf("the same");
	return 0;
}

@函数名称: memmove
函数原型: void *memmove(void *dest, const void *src, size_t n)
函数功能: 字符串拷贝
函数返回: 指向dest的指针
参数说明: src-源字符串,n-拷贝的最大长度
所属文件: ,

#include 
#include 
int main()
{
	char dest[40]="abcdefghijklmnopqrstuvwxyz0123456789";
	printf("destination prior to memmove:%s\n",dest);
	memmove(dest+1,dest,35);
	printf("destination after memmove:%s",dest);
	return 0;
}

@函数名称: memset
函数原型: void *memset(void *s, int c, size_t n)
函数功能: 字符串中的n个字节内容设置为c
函数返回:
参数说明: s-要设置的字符串,c-设置的内容,n-长度
所属文件: ,

#include 
#include 
#include 
int main()
{
	char buffer[]="Hello world";
	printf("Buffer before memset:%s\n",buffer);
	memset(buffer,'*',strlen(buffer)-1);
	printf("Buffer after memset:%s",buffer);
	return 0;
} 

C++ string类的一些成员函数

string类的构造函数:
string(const char *s); //用c字符串s初始化
string(int n,char c); //用n个字符c初始化
此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2=”hello”;都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常

string类的字符操作:
const char &operator[](int n)const;
const char &at(int n)const;
char &operator[](int n);
char &at(int n);
operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。
const char *data()const;//返回一个非null终止的c字符数组
const char *c_str()const;//返回一个以null终止的c字符串
int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目

string的特性描述:
int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)
int max_size()const; //返回string对象中可存放的最大字符串的长度
int size()const; //返回当前字符串的大小
int length()const; //返回当前字符串的长度
bool empty()const; //当前字符串是否为空
void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分

string类的输入输出操作:
string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。
函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符’\n’分开。

string的赋值:
string &operator=(const string &s);//把字符串s赋给当前字符串
string &assign(const char *s);//用c类型字符串s赋值
string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值
string &assign(const string &s);//把字符串s赋给当前字符串
string &assign(int n,char c);//用n个字符c赋值给当前字符串
string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串
string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串

string的连接:
string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾
string &append(const char *s); //把c类型字符串s连接到当前字符串结尾
string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾
string &append(const string &s); //同operator+=()
string &append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾
string &append(int n,char c); //在当前字符串结尾添加n个字符c
string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾

string的比较:
bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等
运算符”>”,”<“,”>=”,”<=”,”!=”均被重载用于字符串的比较;
int compare(const string &s) const;//比较当前字符串和s的大小
int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小
int compare(int pos, int n,const string &s,int pos2,int n2)const;//比较当前字符串从pos开始的n个字符组成的字符串与s中pos2开始的n2个字符组成的字符串的大小
int compare(const char *s) const;
int compare(int pos, int n,const char *s) const;
int compare(int pos, int n,const char *s, int pos2) const;
compare函数在>时返回1,<时返回-1,==时返回0

string的子串:
string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串

string的交换:
void swap(string &s2); //交换当前字符串与s2的值

string类的查找函数:

int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
//查找成功时返回所在位置,失败返回string::npos的值

int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;
//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值

int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置
int find_first_of(const char *s, int pos = 0) const;
int find_first_of(const char *s, int pos, int n) const;
int find_first_of(const string &s,int pos = 0) const;
//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos

int find_first_not_of(char c, int pos = 0) const;
int find_first_not_of(const char *s, int pos = 0) const;
int find_first_not_of(const char *s, int pos,int n) const;
int find_first_not_of(const string &s,int pos = 0) const;
//从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos

int find_last_of(char c, int pos = npos) const;
int find_last_of(const char *s, int pos = npos) const;
int find_last_of(const char *s, int pos, int n = npos) const;
int find_last_of(const string &s,int pos = npos) const;

int find_last_not_of(char c, int pos = npos) const;
int find_last_not_of(const char *s, int pos = npos) const;
int find_last_not_of(const char *s, int pos, int n) const;
int find_last_not_of(const string &s,int pos = npos) const;
//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找

string类的替换函数:

string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串

string类的插入函数:

string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c

string类的删除函数

iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串

string类的迭代器处理:

string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。
用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:
const_iterator begin()const;
iterator begin(); //返回string的起始位置
const_iterator end()const;
iterator end(); //返回string的最后一个字符后面的位置
const_iterator rbegin()const;
iterator rbegin(); //返回string的最后一个字符的位置
const_iterator rend()const;
iterator rend(); //返回string第一个字符位置的前面
rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现

字符串流处理:

通过定义ostringstream和istringstream变量实现,头文件中
例如:
string input(“hello,this is a test”);
istringstream is(input);
string s1,s2,s3,s4;
is>>s1>>s2>>s3>>s4;//s1=”hello,this”,s2=”is”,s3=”a”,s4=”test”
ostringstream os;
os<<<<
cout<

gcc的内存对齐

以下转自http://bigwhite.blogbus.com/logs/1347304.html

====================================

在最近的项目中,我们涉及到了“内存对齐”技术。对于大部分程序员来说,“内存对齐”对他们来说都应该是“透明的”。“内存对齐”应该是编译器的“ 管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。

一、内存对齐的原因
大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

二、对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

三、试验
我们通过一系列例子的详细说明来证明这个规则吧!
我试验用的编译器包括GCC 3.4.2和VC6.0的C编译器,平台为Windows XP + Sp2。

我们将用典型的struct对齐来说明。首先我们定义一个struct:
#pragma pack(n) /* n = 1, 2, 4, 8, 16 */
struct test_t {
int a;
char b;
short c;
char d;
};
#pragma pack(n)
首先我们首先确认在试验平台上的各个类型的size,经验证两个编译器的输出均为:
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4

我们的试验过程如下:通过#pragma pack(n)改变“对齐系数”,然后察看sizeof(struct test_t)的值。

1、1字节对齐(#pragma pack(1))
输出结果:sizeof(struct test_t) = 8 [两个编译器输出一致]
分析过程:
1) 成员数据对齐
#pragma pack(1)
struct test_t {
int a; /* 长度4 > 1 按1对齐;起始offset=0 0%1=0;存放位置区间[0,3] */
char b; /* 长度1 = 1 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */
short c; /* 长度2 > 1 按1对齐;起始offset=5 5%1=0;存放位置区间[5,6] */
char d; /* 长度1 = 1 按1对齐;起始offset=7 7%1=0;存放位置区间[7] */
};
#pragma pack()
成员总大小=8

2) 整体对齐
整体对齐系数 = min((max(int,short,char), 1) = 1
整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 8 /* 8%1=0 */ [注1]

2、2字节对齐(#pragma pack(2))
输出结果:sizeof(struct test_t) = 10 [两个编译器输出一致]
分析过程:
1) 成员数据对齐
#pragma pack(2)
struct test_t {
int a; /* 长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */
char b; /* 长度1 < 2 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 2 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ }; #pragma pack() 成员总大小=9 2) 整体对齐 整体对齐系数 = min((max(int,short,char), 2) = 2 整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 10 /* 10%2=0 */ 3、4字节对齐(#pragma pack(4)) 输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(4) struct test_t { int a; /* 长度4 = 4 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 4 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 4 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 4 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ }; #pragma pack() 成员总大小=9 2) 整体对齐 整体对齐系数 = min((max(int,short,char), 4) = 4 整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 12 /* 12%4=0 */ 4、8字节对齐(#pragma pack(8)) 输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(8) struct test_t { int a; /* 长度4 < 8 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 8 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 8 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 8 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ }; #pragma pack() 成员总大小=9 2) 整体对齐 整体对齐系数 = min((max(int,short,char), 8) = 4 整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 12 /* 12%4=0 */ 5、16字节对齐(#pragma pack(16)) 输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(16) struct test_t { int a; /* 长度4 < 16 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 16 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 16 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 16 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ }; #pragma pack() 成员总大小=9 2) 整体对齐 整体对齐系数 = min((max(int,short,char), 16) = 4 整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 12 /* 12%4=0 */ 四、结论 8字节和16字节对齐试验证明了“规则”的第3点:“当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果”。另外内存对齐是个很复杂的东西,上面所说的在有些时候也可能不正确。呵呵^_^ [注1] 什么是“圆整”? 举例说明:如上面的8字节对齐中的“整体对齐”,整体大小=9 按 4 圆整 = 12 圆整的过程:从9开始每次加一,看是否能被4整除,这里9,10,11均不能被4整除,到12时可以,则圆整结束。

va_list、va_start、va_arg、va_end的原理与使用

参考:http://hi.baidu.com/blog101/blog/item/887a70fa1f6d071ba9d3115f.html

1. 概述
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人采用指针参数来解决问题.下面就c语言中处理不定参数数目的问题进行讨论.
2. 定义
大家先看几宏.
在VC++6.0的include有一个stdarg.h头文件,有如下几个宏定义:

      #define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
      #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )           //第一个可选参数地址
      #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
      #define va_end(ap)    ( ap = (va_list)0 )                            // 将指针置为无效

如果对以上几个宏定义不理解,可以略过,接这看后面的内容.
3. #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) – 1) )
的目的在于把sizeof(n)的结果变成至少是sizeof(int)的整倍数,这个一般用来
在结构中实现按int的倍数对齐。
如果sizeof(int)是4,那么,当sizeof(n)的结果在1~4之间时,_INTSIZEOF(n)的
结果会是4;当sizeof(n)的结果在5~8时,_INTSIZEOF(n)的结果会是8;当sizeof(n)
的结果在9~12时,_INTSIZEOF(n)的结果会是12;……总之,会是sizeof(int)的倍数
4. 参数在堆栈中分布,位置
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码, 这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的.
总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.
堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:
最后一个参数
倒数第二个参数

第一个参数
函数返回地址
函数代码段
5. 示例:

1)简单示例(一个可变参数):

#include "afx.h"
#include "stdio.h"
#include "stdarg.h"

void arg_test(int i, ...);

char *buff=NULL;


int main(int argc,char *argv[])
{
	int int_size = _INTSIZEOF(int);
	printf("int_size=%d\n", int_size);
	
	
	HANDLE hData=GlobalAlloc(GPTR,100);
	buff=(char*)GlobalLock(hData);
	
	arg_test(0,"ok,hello world!");
	
	GlobalUnlock(buff);
	GlobalFree(hData);
	
	return 0;
}

void arg_test(int i, ...)
{
	va_list arg_ptr;
	
	//使用此句表明arg_ptr将指向第一个可选参数地址,即i后面第一个参数的地址
	va_start(arg_ptr, i);
	printf("&i = %p\n", &i);//打印参数i在堆栈中的地址
	printf("arg_ptr = %p\n", arg_ptr);
	//打印va_start之后arg_ptr地址,
	//应该比参数i的地址高sizeof(int)个字节
	//这时arg_ptr指向下一个参数的地址
	
	wvsprintf(buff,"%s\r\n",arg_ptr);
	printf("%d \r\n%s\n", i, buff);
}

2)多个可变参数(循环读取)
//第一个参数定义可选参数个数(总的参数个数减去一),用于循环取初参数内容

#include "afx.h"
#include "stdio.h"
#include "stdarg.h"

void arg_cnt(int cnt, ...);

int main(int argc,char *argv[])
{
	int int_size = _INTSIZEOF(int);
	printf("int_size=%d\n", int_size);
	arg_cnt(4,1,2,3,4);
	return 0;
}

void arg_cnt(int cnt, ...)
{
	int value=0;
	int i=0;
	va_list arg_ptr;
	va_start(arg_ptr, cnt);
	for(i = 0; i < cnt; i++)
	{
		value = va_arg(arg_ptr,int);
		printf("value%d=%d\n", i+1, value);
	}
}

3)自定义可变参数类型

#include "afx.h"
#include "stdio.h"
#include "stdarg.h"

const int INT_TYPE   = 100000;
const int STR_TYPE   = 100001;
const int CHAR_TYPE   = 100002;
const int LONG_TYPE   = 100003;
const int FLOAT_TYPE = 100004;
const int DOUBLE_TYPE = 100005;
//第一个参数定义可选参数个数,用于循环取初参数内容
//可变参数采用arg_type,arg_value...的形式传递,以处理不同的可变参数类型
void arg_type(int cnt, ...);
//测试va_start,va_arg的使用方法,函数参数在堆栈中的地址分布情况
void *buff=NULL;

int main(int argc,char *argv[])
{
	int int_size = _INTSIZEOF(int);
	printf("int_size=%d\n", int_size);
	HANDLE hData=GlobalAlloc(GPTR,100);
	buff=GlobalLock(hData);
	arg_type(2, INT_TYPE, 222, STR_TYPE, "ok,hello world!");
	GlobalUnlock(buff);
	GlobalFree(hData);
	return 0;
}

void arg_type(int cnt, ...)
{
	int arg_type = 0;
	int int_value=0;
	int i=0;
	// int arg_cnt=cnt;
	char *str_value = NULL;
	va_list arg_ptr;
	va_start(arg_ptr, cnt);
	int len=0;
	for(i = 0; i < cnt; i++)
	{
		arg_type = va_arg(arg_ptr,int);
		switch(arg_type)
		{
			case INT_TYPE:
				int_value = va_arg(arg_ptr,int);
			
				len=wvsprintf((char*)buff,"%d\r\n",arg_ptr);
				printf("type=%d address=%s",arg_type,buff);
			
				printf("value%d=%d\n", i+1, int_value);
				break;
			case STR_TYPE:
				str_value = va_arg(arg_ptr,char*);
			
				wvsprintf((char*)buff+len,"%x\r\n",arg_ptr);
				printf("len=%d type=%d address=%s\r\n",len,arg_type,buff);
			
				printf("value%d=%s\n", i+1, str_value);
				break;
			default:
				break;
		}
	}
}

堆和栈的区别——给初学者

堆和栈的区别——给初学者
http://linux.chinaunix.net/bbs/viewthread.php?tid=1119653&extra=page%3D1

一、预备知识—程序的内存分配

由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后有系统释放 。
4、文字常量区: 常量字符串就是放在这里的, 程序结束后由系统释放。
5、程序代码区: 存放函数体的二进制代码。

Example:

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″优化成一个地方。
}

二、堆和栈的理论知识

2.1 申请方式
栈: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
堆: 需要程序员自己申请,并指明大小,在c中malloc函数:如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。

2.2 申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3 申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

2.4 申请效率的比较:
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5 堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6 存取效率的比较
char s1[] = “aaaaaaaaaaaaaaa”;
char *s2 = “bbbbbbbbbbbbbbbbb”;
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = “1234567890”;
char *p =”1234567890″;
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7 小结:
堆和栈的区别可以用如下的比喻来看出: 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。栈的空间大小有限定,VC的缺省是2M。栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。有一点必须知道,当一个函数调用完返回后它会释放该函数中所有的栈空间。栈是由编译器自动管理的,不用你操心。堆是动态分配内存的,并且你可以分配使用很大的内存。但是用不好会产生内存泄漏。并且频繁地malloc和free会产生内存碎片(有点类似磁盘碎片),因为C分配动态内存时是寻找匹配的内存的。而用栈则不会产生碎片。在栈上存取数据比通过指针在堆上存取数据快些。一般大家说的堆栈和栈是一样的,就是栈(stack),而说堆时才是堆heap。栈是先入后出的,一般是由高地址向低地址生长。

内存的堆分配和栈分配 & 字符数组,字符指针,Sizeof总结

内存的堆分配和栈分配 & 字符数组,字符指针,Sizeof总结
http://hi.baidu.com/anglecloudy/blog/item/c2b27045c5721020cefca33d.html

堆和栈的区别

一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其
操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
一块区域。 – 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序
这是一个前辈写的,非常详细
//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″优化成一个地方。
}
二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。
2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
2.6存取效率的比较
char s1[] = “aaaaaaaaaaaaaaa”;
char *s2 = “bbbbbbbbbbbbbbbbb”;
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#i nclude
void main()
{
char a = 1;
char c[] = “1234567890”;
char *p =”1234567890″;
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。
2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
———————————————————————————————————————-
全局变量或者静态变量,它们都放在堆里的
局部变量放在栈里的
堆区,也叫自由存储区.
为什么说在堆上分配内存比在栈上分配内存慢?堆空间的开辟需要用系统函数,栈上直接修改指针
堆空间的管理需要系统记帐,栈上的空间可以由编译器管理或是保存在某个处理器寄存器中。
堆空间的释放需要系统管理,栈上的释放可以直接丢弃。堆空间需要通过栈上的指针间接引用,所以访问会慢

记得在apue2上面看到关于线程中有这样一段话,大致意思是,一个线程有自己的堆栈,可以在堆栈上分配内存,比如说一个结构体,如果这个线程调用了pthread_exit()返回这个结构体指针的时候之后要特别的小心,因为很有可能这个结构体里面的成员值发生改变,这个可以理解,因为同一个进程所有线程的资源是共享的,当这个线程退出之后那部分以前用过的堆栈很可能被其它线程占用,但同时又说如果malloc就不会出现这样的问题,

比如,在栈上分一个int,只要esp-4就可以了,
在堆上系统要记录被分配内存的信息,以便释放
BTW:
栈有序
堆无序

----------------------------------

内存分配方式有三种:

1.从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

2.在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3.从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

----------------------------------------

一般所说的堆栈(stack)往往是指栈,先进后出,它是一块内存区。用以存放程序的局部变量,临时变量,函数的参数,返回地址等。在这块区域中的变量的分配和释放由系统自动进行。不需要用户的参与。
而在堆(heap,先进先出)上的空间则是由用户进行分配,并由用户负责释放。

===================================================================================

字符数组,字符指针,Sizeof总结1.以字符串形式出现的,编译器都会为该字符串自动添加一个0作为结束符,如在代码中写 “abc”,那么编译器帮你存储的是”abc\0″2.”abc”是常量吗?答案是有时是,有时不是。
不是常量的情况:”abc”作为字符数组初始值的时候就不是,如 char str[] = “abc”;因为定义的是一个字符数组,所以就相当于定义了一些空间来存放”abc”,而又因为字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为 char str[3] = {‘a’,’b’,’c’};又根据上面的总结1,所以 char str[] = “abc”;的最终结果是 char str[4] = {‘a’,’b’,’c’,’\0′};做一下扩展,如果char str[] = “abc”;是在函数内部写的话,那么这里 的”abc\0″因为不是常量,所以应该被放在栈上。是常量的情况: 把”abc”赋给一个字符指针变量时,如 char* ptr = “abc”; 因为定义的是一个普通指针,并没有定义空间来存放”abc”,所以编译器得帮我们找地方来放”abc”,显然,把这里的”abc”当成常量并把它放到程序 的常量区是编译器 最合适的选择。所以尽管ptr的类型不是const char*,并且ptr[0] = ‘x’;也能编译 通过,但是执行ptr[0] = ‘x’;就会发生运行时异常,因为这个语句试图去修改程序 常量区中的东西。记得哪本书中曾经说过char* ptr = “abc”;这种写法原来在c++标准中是不允许的, 但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许, 但是建议的写法应该是const char* ptr = “abc”;这样如果后面写ptr[0] = ‘x’的话编译器就不会让它编译通过,也就避免了上面说的运行时异常。 又扩展一下,如果char* ptr = “abc”;写在函数体内,那么虽然这里的”abc\0″被放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的, 只不过是它所指向的东西被放在常量区罢了。3.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。 如char s1[3]和char s2[4],s1的类型就是char[3],s2的类型就是char[4], 也就是说尽管s1和s2都是字符数组,但两者的类型却是不同的。4.字符串常量的类型可以理解为相应字符常量数组的类型, 如”abcdef”的类型就可以看成是const char[7]5.sizeof是用来求类型的字节数的。如int a;那么无论sizeof(int)或者是sizeof(a)都 是等于4,因为sizeof(a)其实就是sizeof(type of a)6.对于函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通 的指针类型,如对于void func(char sa[100],int ia[20],char *p) 则sa的类型为char*,ia的类型为int*,p的类型为char*7.根据上面的总结,来实战一下: 对于char str[] = “abcdef”;就有sizeof(str) == 7,因为str的类型是char[7], 也有sizeof(“abcdef”) == 7,因为”abcdef”的类型是const char[7]。 对于char *ptr = “abcdef”;就有sizeof(ptr) == 4,因为ptr的类型是char*。 对于char str2[10] = “abcdef”;就有sizeof(str2) == 10,因为str2的类型是char[10]。 对于void func(char sa[100],int ia[20],char *p); 就有sizeof(sa) == sizeof(ia) == sizeof(p) == 4, 因为sa的类型是char*,ia的类型是int*,p的类型是char*。

字节序问题–大端法小端法

字节序问题–大端法小端法
http://www.cnblogs.com/wqlblogger/archive/2008/01/25/1052915.html
一、字节序定义

字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。

其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。

在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于 TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。比如,以太网头部中2字节的“以太网帧类型”,表示后面数据的类型。对于ARP请求或应答的以太网帧类型来说,在网络传输时,发送的顺序是0x08,0x06。在内存中的映象如下图所示:
栈底 (高地址)
—————
0x06 — 低位
0x08 — 高位
—————
栈顶 (低地址)
该字段的值为0x0806。按照大端方式存放在内存中。

二、高/低地址与高低字节

首先我们要知道我们C程序映像中内存的空间布局情况:在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明,大致如下图:
———————– 最高内存地址 0xffffffff
| 栈底
.
. 栈
.
栈顶
———————–
|
|
\|/

NULL (空洞)

/|\
|
|
———————–

———————–
未初始化的数据
—————-(统称数据段)
初始化的数据
———————–
正文段(代码段)
———————– 最低内存地址 0x00000000

以上图为例如果我们在栈上分配一个unsigned char buf[4],那么这个数组变量在栈上是如何布局的呢[注1]?看下图:
栈底 (高地址)
———-
buf[3]
buf[2]
buf[1]
buf[0]
———-
栈顶 (低地址)

现在我们弄清了高低地址,接着来弄清高/低字节,如果我们有一个32位无符号整型0x12345678(呵呵,恰好是把上面的那4个字节buf看成一个整型),那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。

高低地址和高低字节都弄清了。我们再来回顾一下Big-Endian和Little-Endian的定义,并用图示说明两种字节序:
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
Big-Endian: 低地址存放高位,如下图:
栈底 (高地址)
—————
buf[3] (0x78) — 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) — 高位
—————
栈顶 (低地址)

Little-Endian: 低地址存放低位,如下图:
栈底 (高地址)
—————
buf[3] (0x12) — 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) — 低位
—————
栈顶 (低地址)

在现有的平台上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。

三、例子

嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址 存放内容
0x4001 0x12
0x4000 0x34

而在Big-endian模式CPU内存中的存放方式则为:

内存地址 存放内容
0x4001 0x34
0x4000 0x12

32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址 存放内容
0x4003 0x12
0x4002 0x34
0x4001 0x56
0x4000 0x78

而在Big-endian模式CPU内存中的存放方式则为:

内存地址 存放内容
0x4003 0x78
0x4002 0x56
0x4001 0x34
0x4000 0x12