深入理解sizeof

一、好首先看看sizeof和strlen在MSDN上的定义:

首先看一MSDN上如何对sizeof进行定义的:
sizeof Operator

sizeof expression

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type 
(including aggregate types). This keyword returns a value of type size_t.

The expression is either an identifier or a type-cast expression (a type specifier enclosed in 
parentheses).

When applied to a structure type or variable, sizeof returns the actual size, which may include 
padding bytes inserted for alignment. When applied to a statically dimensioned array, sizeof 
returns the size of the entire array. The sizeof operator cannot return the size of dynamically 
allocated arrays or external arrays.

然后再看一下对strlen是如何定义的:

strlen

Get the length of a string.

Routine Required Header:
strlen <string.h>

size_t strlen( const char *string );
Parameter
string:Null-terminated string 
Libraries
All versions of the C run-time libraries.

Return Value
Each of these functions returns the number of characters in string, excluding the terminal 
NULL. No return value is reserved to indicate an error.

Remarks
Each of these functions returns the number of characters in string, not including the 
terminating null character. wcslen is a wide-character version of strlen; the argument of 
wcslen is a wide-character string. wcslen and strlen behave identically otherwise.
二、由几个例子说开去。

第一个例子:
char* ss = "0123456789";
sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针
sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[] = "0123456789";
sizeof(ss) 结果 11 ===》ss是数组,计算到/0位置,因此是10+1
sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[100] = "0123456789";
sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到/0为止之前

int ss[100] = "0123456789";
sizeof(ss) 结果 400 ===》ss表示再内存中的大小 100×4
strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''/0''结尾的

char q[]="abc";
char p[]="a/n";
sizeof(q),sizeof(p),strlen(q),strlen(p);
结果是 4 3 3 2      
第二个例子:
class X
{
int i;
int j;
char k;
};
X x;
cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐
cout<<sizeof(x)<<endl; 结果 12 同上
第三个例子:
char szPath[MAX_PATH]
  如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)

三、sizeof深入理解。
  • 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
  • 2.sizeof是算符,strlen是函数。
  • 3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''/0''结尾的。sizeof还可以用函数做参数,比如:
    short f();
    printf("%d/n", sizeof(f()));
    
    输出的结果是sizeof(short),即2。
  • 4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
  • 5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
    char str[20]="0123456789";
    int a=strlen(str); //a=10;
    int b=sizeof(str); //而b=20;
    
  • 6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
  • 7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
  • 8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺 寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
  • 9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
    fun(char [8])
    fun(char [])
    
    都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小, 需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去
    fun(unsiged char *p1, int len)
    {
      unsigned char* buf = new unsigned char[len+1]
      memcpy(buf, p1, len);
    }
    
    有关内容见: C++ PRIMER?
  • 10.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
  • 11.sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式
四、结束语

sizeof使用场合。
  • 1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如: 
      void *malloc(size_t size), 
      size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
    
  • 2.用它可以看看一类型的对象在内存中所占的单元字节。
    void * memset(void * s,int c,sizeof(s))
    
  • 3.在动态分配一对象时,可以让系统知道要分配多少内存。
  • 4.便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。
  • 5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
  • 6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是程序的完整实现: //定义栈结构体 typedef struct { int *data; //存储数据的数组指针 int top; //栈顶指针 int size; //栈的最大容量 } Stack; //初始化栈 void initStack(Stack *s, int size) { s->data = (int*)malloc(sizeof(int) * size); //动态分配数组空间 s->top = -1; //栈顶指针初始化为-1 s->size = size; //记录栈的最大容量 } //释放栈 void freeStack(Stack *s) { free(s->data); //释放数组空间 s->top = -1; //栈顶指针重置为-1 s->size = 0; //栈的最大容量重置为0 } //判断栈是否为空 int isEmpty(Stack *s) { return s->top == -1; } //判断栈是否已满 int isFull(Stack *s) { return s->top == s->size - 1; } //入栈 void push(Stack *s, int x) { if (isFull(s)) { //如果栈已满,无法入栈 printf("Stack is full!\n"); return; } s->data[++s->top] = x; //栈顶指针先加1,再将数据x存入栈顶位置 } //出栈 int pop(Stack *s) { if (isEmpty(s)) { //如果栈为空,无法出栈 printf("Stack is empty!\n"); return -1; } return s->data[s->top--]; //先返回栈顶元素,再将栈顶指针减1 } //测试代码 int main() { Stack s; initStack(&s, 5); //初始化栈,最大容量为5 push(&s, 1); push(&s, 2); push(&s, 3); printf("%d\n", pop(&s)); //输出3 printf("%d\n", pop(&s)); //输出2 push(&s, 4); push(&s, 5); push(&s, 6); //栈已满,无法入栈 freeStack(&s); //释放栈 return 0; } ### 回答2: 栈和队列是计算机中常用的数据结构,对于掌握计算机编程技术以及解决实际问题都有很大的帮助。栈和队列都是线性结构,栈是一种后进先出的操作模式,而队列则是先进先出的操作模式。本实验的目的旨在帮助学生掌握这两种数据结构的基本知识,并深入理解它们的特征,掌握并灵活运用这两种操作模式。同时,通过实现栈的各种基本操作,如初始化、释放栈、入栈、出栈等,帮助学生更好地理解和掌握栈这种数据结构。 在实现栈的基本操作时,首先需要定义一个栈的数据结构。可以使用顺序结构来表示栈,也可以使用链式结构。对于顺序结构,可以使用数组来实现。下面对于栈的各种基本操作进行介绍: 1、初始化栈:在使用栈之前,需要分配一定的内存空间,并初始化各个变量。可以使用malloc来动态分配内存空间,也可以使用静态数组来实现。具体代码实现为: ``` #define STACK_SIZE 10 typedef struct { int data[STACK_SIZE]; int top; } Stack; int initStack(Stack *stack) { stack->top = -1; return 0; } ``` 2、释放栈:在使用完毕栈之后,需要将栈所占用的内存空间进行释放。如果使用的是动态分配的内存空间,就可以使用free来进行释放。具体代码实现为: ``` int releaseStack(Stack *stack) { free(stack); return 0; } ``` 3、入栈:将一个数据元素压入栈中,需要先判断栈是否已经满了。如果栈满了,则入栈失败。具体代码实现为: ``` int push(Stack *stack, int data) { if(stack->top >= STACK_SIZE - 1) { return -1; } stack->top++; stack->data[stack->top] = data; return 0; } ``` 4、出栈:将一个数据元素弹出栈中,需要先判断栈是否为空。如果栈为空,则出栈失败。具体代码实现为: ``` int pop(Stack *stack, int *data) { if(stack->top == -1) { return -1; } *data = stack->data[stack->top]; stack->top--; return 0; } ``` 通过实现栈的上述基本操作,可以帮助学生更好地理解和掌握栈这种数据结构的特征,并能够很好地应用到实际问题中去。同时,通过这种方式,也可以让学生更加深入理解计算机编程技术中的数据结构和算法,对于提高计算机编程水平和解决实际问题都有很大的帮助。 ### 回答3: 栈和队列是计算机科学中常见的数据结构,它们分别具有先进先出和后进先出的特点。栈和队列的基本操作包括初始化、入栈(入队)、出栈(出队)和释放内存等。 栈的初始化可以通过定义一个固定大小的数组,并初始化栈顶指针为-1来实现。数组的大小应根据需要调整。释放栈时,只需将栈顶指针重置为-1即可完成操作。 入栈时,需要先判断栈是否已满,若栈已满,则提示“栈已满”并返回。否则,将新元素压入栈顶,同时栈顶指针加1即可完成入栈操作。 出栈时,首先需要判断栈是否为空,若栈为空,则提示“栈为空”并返回。否则,将栈顶元素弹出,并将栈顶指针减1即可完成出栈操作。 顺序结构表示栈可以使用数组来实现,数组的元素类型为栈存储的数据类型。在定义数组时,可以设置一个固定大小的数组,并初始化栈顶指针为-1。在进行栈操作时,需要判断栈是否已满或者为空,以防止出现数组越界或者栈错误的情况。栈操作应当遵循LIFO(Last In First Out)原则,即后进先出的规则。 在程序设计过程中,需要注意代码的可读性和可维护性。为了使代码易于理解和维护,可以通过函数封装和注释等方式来提高代码质量和可读性。同时,为了提高程序的可靠性,应该在程序中设置异常处理机制,以捕获和处理各种异常情况。 综上所述,掌握栈和队列的基本知识并能够正确地实现栈和队列的各种基本操作,对于编写高质量的程序和提高编程能力是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值