做一些笔试题目时,经常会遇到sizeof和strlen区别,static和const的使用等,一直搞不清,最近看看书,稍微懂了一点。
一、总结sizeof和strlen区别
//求字符串长度用strlen(),求内存空间大小用sizeof
关于sizeof
1.sizeof(...)是运算符,结果类型是size_t,在头文件中typedef为unsigned int类型
sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
2.其值在编译时即计算好了,由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。
3.参数可以是数组、指针、类型、对象、函数等
4.它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。
实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
类型——该类型所占的空间大小;
int 4;short 2;long 4;float 4;double 8;char 1;long double 12;
char a[10];sizeof(a)//结果为10
int a[10];sizeof(a)//结果为40
数组——编译时分配的数组空间大小;
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;分配的数组str[20]所占的内存空间的大小,不受里面存储的内容改变。
//sizeof返回定义的数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。
//strlen只关心存储的数据内容,不关心空间的大小和类型。
char *parr = new char[10];
int len_one = strlen(parr);//取决于parr里面存了什么,从parr[0]开始直到第一个NULL结束,字符串长度
int len_two = sizeof(parr);//sizeof认为parr是个字符指针,因此返回的是该指针所占的空间,4
int len_three = sizeof(*parr);//*parr所代表的是parr所指的地址空间存放的字符,所以长度为1
//指针和数组结果是不一样的
对象——对象的实际占用空间大小;(结构体)
//因为对齐问题使结构体的sizeof变得比较复杂总体上遵循两个原则:
(1)整体空间是占用空间最大的成员(的类型)所占字节数的整倍数
(2)数据对齐原则----内存按结构成员的先后顺序排列,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整倍数,如果不够则补齐
函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
short f();
printf("%d\n", sizeof(f())); //输出的结果是sizeof(short),即2。
1.strlen(...)是函数
2.要在运行时才能计算。
3.参数必须是字符型指针(char*),且必须是以'\0'结尾的
当数组名作为参数传入时,实际上数组就退化成指针了。只能接受char型指针
int ac[10];
cout<<strlen(ac)<<endl; //ac相当于一个指针,但是strlen只能接受char*类型,所以编译时出错!!!
4.它的功能是:返回字符串的长度。从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。
返回的长度大小不包括NULL。
没有给它赋初值,这个结果是不定的,它会从字符串首地址一直找下去,直到遇到'\0'停止
char a[10];cout<<strlen(a)<<endl;//结果不定
char a[10]={'\0'};cout<<strlen(a)<<endl;//结果为0
char a[10]="Jun";cout<<strlen(a)<<endl;//结果为3
二、static用法总结
1.用static声明局部变量与auto相比,static局部变量有三点不同
(1)存储空间分配不同
auto类型分配在栈上,属于动态存储类别,占动态存储空间,函数调用结束后自动释放;
static分配在静态存储区,在程序整个运行期间都不释放。
(2)static局部变量只赋初值一次,以后每次调用时不赋新值只是保留上次函数调用结束时的值;
对auto变量赋值,每调用一次函数重新给一次初值。
(3)对静态局部变量,默认值为0或空字符;对自动变量,默认值是不确定的
#include <stdio.h>
void main()
{
int f(int);
int a=2,i;
for(i=0;i<3;i++)
printf("%d",f(a));
}
int f(int a)
{
auto int b=0;//auto可省略
static int c=3;
b=b+1;c=c+1;
return (a+b+c);
}
//i=0:a+b+c=2+1+4
//i=1:a+b+c=2+1+5
//i=2:a+b+c=2+1+6
2.用static声明全局变量
该全局变量只能用于本文件,可独立的在不同的文件中使用相同的全局变量而互不相干,可降低各文件之间的耦合性
static/auto两种形式的全局变量(外部变量)都是静态存储方式,都是编译时分配存储空间,但作用域不同(加static使得该全局变量只限于本文件使用)
使用静态外部变量,有利于隔离错误,有利于模块化程序设计。
如何声明所有cpp可共享的全局变量,在头文件里声明为extern:
extern int g_value; // 注意,不要初始化值!
int g_value = 0; //然后在其中任何一个包含该头文件的cpp中初始化(一次)就好:
// 初始化一样不要extern修饰,因为extern也是声明性关键字;
// 然后所有包含该头文件的cpp文件都可以用g_value这个名字访问相同的一个变量;
class Type
{
private:
int a;
static int h;
public:
void print();
Type(int x=0);
static int i;
};
void Type::print()
{
cout<<"a="<<++a;
cout<<" h="<<++h<<endl;
}
Type::Type(int x)
{
a=x;
}
int Type::h=0;//静态数据成员赋初值在类体外进行,前面不再加static
void main()
{ //静态数据成员在编译时创建并初始化,故在该类的任何对象被创建前已经存在
//所以公有的静态数据成员可在对象定义前被访问——类名::公有静态成员变量名
Type::i=9;
Type t1,t2,t3;
t1.print();//a=1 h=1
t2.print();//a=1 h=2
t3.print();//a=1 h=3
//a变量为每个对象各自拥有,h为三个对象共有
}
(1)静态数据成员的初始化必须在类外进行,默认值为0;(前面不加static)
(2)可在同一个类的不同对象之间提供数据共享。
(3)对于公有的静态数据成员可在对象定义前被访问;在对象定义后,还可对象名.变量名(t1.i)
私有的静态数据成员不能被类的外部函数访问,也不能用对象进行访问
(private 只允许被该类的成员函数即友元访问)
4.静态成员函数
(1)静态成员函数只能访问静态数据成员
(2)可通过对象或类名进行调用
类名::静态成员函数名(实参表)---所以在建立任何对象之前可以用静态成员函数处理静态数据成员
对象名.静态成员函数名(实参表)
(3)初始化必须在类外进行
(4)静态成员函数没有this指针,而非静态成员函数有一个纸箱当前对象的this指针
#include <iostream.h>
class Type
{
private:
int a;
static int s;
public:
static void print();
Type();
};
void Type::print()
{
cout<<"s="<<s<<endl;//静态成员函数只能访问静态数据成员
}
Type::Type()
{
a=0;
s++;
cout<<"a="<<++a<<endl;
}
int Type::s //静态数据成员默认初值为0
void main()
{
Type::print();//在未定义对象前,可用类名来调用静态成员函数
Type t1,t2;
t1.print();//也可用对象来调用静态成员函数
t2.print();
}
//结果:s=0
// a=1
// a=1
// s=2
// s=2
还有const待整理。。。。