sizeof strlen strncpy用法总结 结构体实际所占内存大小 以及memset用法

sizeof测类型(数组名除外) strlen测实际长度 strncpy返回指针类型

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 int main()
 5 {
 6     char *p="wangddd";
 7     printf("%d\n",sizeof(p));//输出4,指针类型
 8 
 9     char x[8];
10     printf("%d\n",sizeof(x));//输出8,所占内存数。注意此处是8*1得出的8,若是int型数组则为8*4得32
11 
12     printf("%s\n",strncpy(x,"wangddddd",sizeof(x)));//返回x指针,只能正常显示前7位,给x赋值时没有自动加上\0, 
13     //strncpy返回值是一个指针x
14     printf("%d\n",sizeof(strncpy(x,"wangddddd",sizeof(x))));//输出4 
15     printf("%d\n",strlen(strncpy(x,"jskjksjdf",sizeof(x))));//随机 取决于编译环境
16     printf("%d\n",strlen(strncpy(x,"jskjkse",sizeof(x))));//输出7,第8位正好是\0
17 
18     char y[5]="w c";
19     printf("%d\n",strlen(y));//输出3
20     printf("%d\n",sizeof(y));//输出5
21 
22     return 0;
23 }

 特殊之处:1 数组名不是指针,但神似指针,因为sizeof(X)打印的是8。具体的解释转载自:http://blog.chinaunix.net/uid-21765995-id-1815661.html

      2 sizeof可以如下使用:    

第一种用法:
  #include <iostream>   using namespace std;   int main(int argc, char* argv[])   {   int i=1;   cout<<sizeof(i)<<<<sizeof(1)<<sizeof 1<<endl;// sizeof(变量名) sizeof(常量名) sizeof 常量 都是可以的,但为了保持规范一般不写第三种   return 0;   }
第二种用法:
  #include <iostream>   using namespace std;   int sum(int a,int b)   {    cout<<a+b<<endl;    return a+b;   } int main(int argc, char* argv[]) {   int i=1;   cout<<sizeof(sum(1,2))<<endl; return 0; }

结果为:4
说明:仅打印了sum函数返回值的类型的大小,并没有调用函数。若sum无返回值则编译提示错误。

函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错误的: 

sizeof( sun );// error 
void foo2() { } 
sizeof( foo2() );// error 
struct S 
{ 
unsigned int f1 : 1; 
unsigned int f2 : 5; 
unsigned int f3 : 12; 
}; 
sizeof( S.f1 );// error

对于结构中变量不能被sizeof计算是由于

让我们交换一下S1中char与int的位置: 

struct S2 
{ 
int i; 
char c; 
}; 

看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。

字节对齐的细节和编译器实现相关,但一般而言,满足三个准则: 
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)
struct S3 
{ 
char c1; 
S1 s; 
char c2; 
}; 

  S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。 c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。

通过上面的叙述,我们可以得到一个公式: 
结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:
sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )

“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。如下: 

struct S5 { }; 
sizeof( S5 ); // 结果为1
#include <stdio.h>
struct student
{
 long id; //4字节

 char name[10]; //10字节

 char sex; //1字节

 int age; //4字节

 float score; //4字节

};
// 4+10+1+1+4+4

int main()
{
    struct student one;
    
    printf("%d", sizeof(struct student));
}
这是我在QQ群里见到有人问的一道问题,结果为24,我说下自己的分析,若有不对还请高手指点,不胜感激。该结构体中最大的基本数据类型为4个字节(数组不是基本类型,被打散着看),所以该结构体的首地址为4的整数倍,id的偏移量为0,因为数组是一个整体,根据数组的sizeof可知其为10个字节,偏移量为sizeof(char)的整数倍,所以char[10]的偏移量为4(id决定),sex的偏移量也是sizeof(char)的整数倍,此时总共占了4+10+1=15个字节,age的偏移量需要是sizeof(int)的整数倍,所以需要在sex后补上一个填充字节,所以age偏移量为16,score的偏移量为16+4=20(可以被4整除),在算上score的4个字节,为24,可以被结构体的最宽基本字节整除,所以整个结构体的sizeof(struct student)为24

对于参数中的数组类型,sizeof计算首地址时认为是指针:

void foo3(char a3[3]) 
{ 
int c3 = sizeof( a3 ); // c3 == 
} 
void foo4(char a4[]) 
{ 
int c4 = sizeof( a4 ); // c4 == 
} 
也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么仔细想想就不难明白,我们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。
memset
内存初始化函数memset()

作用:在一段内存中填充某个给定的值,注意填充时是按照字节顺序填充的,而不是按照元素填充。
此方法是对较大的结构体和数组进行清零操作的一种有效方法。
函数形式:memset(void *buffer,int c,size_t n)
buffer是需要设置的内存的开始地址;c是期望填充值;n是需要填充的字节数。
例1:一个int
a[10]型变量,则memset(a,100,sizeof(int))此操作后,元素a[0]的每个字节的值都是100,即0x64,二进制表示:
01100100,所以元素a[0]为0x64646464,二进制表示:01100100 01100100 01100100 01100100
void main()
{ int i,a[20];
memset(a,10,5*sizeof(int));
for(i=0;i<20;i++)
cout< 此函数输出的10个元素并非10,而是每个字节都是00001010组成的int型数。
例2:
#include
#include
void main( void )
{
char buffer[] = "This is a test of the memset function";
printf( "Before: %s\n", buffer );
memset( buffer, '*', 4 );
printf( "After: %s\n", buffer );
}
Output
Before: This is a test of the memset function
After: **** is a test of the memset function
 
 
Memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为' ''\0';
例:char a[100];
memset(a, '\0', sizeof(a));
memset可以方便地清空一个结构体类型的变量或数组。
如:
struct sample_struct
{
char csName[16];
int iSeq;
int iType;
};
对于变量
struct sample_strcut stTest;
一般情况下,清空stTest的方法:
stTest.csName[0]='\0';
stTest.iSeq=0;
stTest.iType=0;
用memset就非常方便:
memset(&stTest,0,sizeof(struct sample_struct));
如果是数组:
struct sample_struct TEST[10];
则
memset(TEST,0,sizeof(struct sample_struct)*10);

 

memcpy 用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。
例:char a[100],b[50]; memcpy(b, a, sizeof(b));
注意如果用memcpy(b,a,sizeof(a)),很可能会造成b的内存地址溢出。
Strcpy就只能拷贝字符串了,它遇到'\0'就结束拷贝。
例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。
str也可以用用个参数的strncpy(a,b,n)

        

 

posted @ 2015-12-19 22:01  小德cyj  阅读(1721)  评论(0编辑  收藏  举报