zoukankan      html  css  js  c++  java
  • sizeof、strlen、字符串、数组,整到一块,你还清楚吗?

    写在前面

    sizeof、strlen、字符串、数组,提到这些概念,相信学过C语言的人都能耳熟能详,也能谈得头头是道,但是,在实际运用中,当这些内容交织在一起时,大家却不一定能搞地清清楚楚,本文的目的正是帮助大家将相关知识总结清楚。

    正文

    先看一段代码

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void testchar(char str[])
     5 {
     6     printf("%d %d
    ", sizeof(str), strlen(str));
     7 }
     8 
     9 void testint(int arr[])
    10 {
    11     printf("%d
    ", sizeof(arr));
    12 }
    13 
    14 int main()
    15 {
    16     char str[] = "abc";
    17     printf("%d %d
    ", sizeof(str), strlen(str)); //4 3
    18 
    19     char str1[10] = "abc";
    20     printf("%d %d
    ", sizeof(str1), strlen(str1)); //10 3
    21 
    22     char dog[] = "wangwangmiao";
    23     printf("%d %d
    ", sizeof(dog), strlen(dog)); //14 8
    24     testchar(dog); //4 8
    25 
    26     char *cat = "wangwangmiaomiao";
    27     printf("%d %d
    ", sizeof(cat), strlen(cat)); //4 8
    28     
    29     int arr[10] = { 0 };
    30     printf("%d %d
    ", sizeof(arr), sizeof(arr[11])); //40 4
    31     testint(arr); //4
    32 
    33     return 0;
    34 }

     结果

     

    在解释上面的例子之前,我们先来说一说sizeof和strlen。

    语法上的本质不同:

    sizeof是运算符,strlen是函数。

    适用范围不一样:

    对sizeof(name)而言,name可以是变量名也可以是类型名,对strlen而言,参数必须是char*类型的,即strlen仅用于字符串。

    重中之重——从底层看本质

    strlen(ptr)的执行机理是:从参数ptr所指向的内存开始向下计数,直到内存中的内容是全0(即’’)为止(不会对’’进行计数)。用strlen测量字符串的长度,其实就是基于这个原理。

    sizeof(name)的执行机理是:如果name是一个类型名,得到的是该类型的大小(所谓类型的大小,指的是:如果存在一个该类型的变量,这个变量在内存中所占用的字节数),如果name是一个变量名,那么,sizeof(name)并不会真正访问该变量,而是先获知该变量的类型,然后再返回该类型的大小(即便是struct这样的复杂类型,编译器在编译时也会根据它的各个域记录其大小,所以,由类型得到类型大小,不是一件难事)。换句话说,本质上,sizeof的运算对象是类型。如果name是一个变量名,那么,sizeof如何“看待”name的类型,将是一个关键问题。(后面我们会对这一点有深刻的体会)

    上面提到的这一点,是理解好sizeof和strlen的不二法门,是放之四海皆准的准则。下面,我们就以这样的准则来分析上面的例子。

    a.

    char str[] = "abc";
    printf("%d %d
    ", sizeof(str), strlen(str)); //4 3

    这里,是用数组的形式声明字符串,编译器会自动在字符串后面加上'',所以,数组的元素个数是4而不是3。对于sizeof(str)而言,sizeof将str视为char [4]l类型的变量,所以,sizeof(str)的结果就是整个数组所占有的空间大小。对于strlen(str)来说,它从str指向的内存开始计数,直到遇到全0的内存(''),所以最后得到结果3。

    b.

    char str1[10] = "abc";
    printf("%d %d
    ", sizeof(str1), strlen(str1)); //10 3

    编译器为char str1[10]分配10个数组元素大小的空间,这与初始化它的字符串没有关系,所以sizeof(str1)得到10。

    c.

    char dog[] = "wangwangmiao";
    printf("%d %d
    ", sizeof(dog), strlen(dog)); //14 8
    testchar(dog); //4 8

    前两句和a中的情况相同,sizeof(dog)输出整个数组所占的内存大小(包括编译器加上去的''),strlen(dog)遇到''就停止,所以输出8。

    再看后面的函数调用,数组名dog作为函数实参传入,我们再来回顾一下testchar函数

    void testchar(char str[])
    {
        printf("%d %d
    ", sizeof(str), strlen(str));
    }

    我们发现,这里sizeof(str)并没有像sizeof(dog)那样得到14,而是得到了4。这是因为,str是函数形参,尽管它是以数组名的形式出现的,传给它的实参也确实是数组名,但sizeof仅仅把它当成一个char*类型的指针看待,所以,sizeof(str)的结果就是char *类型所占的空间4。至于strlen(str),我们前面说过,它执行的机理就是从str指向的内存开始向下计数,直到遇到'',所以依然得到8。

    d.

    char *cat = "wangwangmiaomiao";
    printf("%d %d
    ", sizeof(cat), strlen(cat)); //4 8 

    由于cat明确声明为char*,所以sizeof将它视为指针,得到4。

    e.

    int arr[10] = { 0 };
    printf("%d %d
    ", sizeof(arr), sizeof(arr[11])); //40 4
    testint(arr); //4

    前面说过,当数组名作为函数形参出现时,sizeof仅仅将其视为一个指针,否则,sizeof认为它代表整个数组,所以,sizeof(arr)得到整个数组所占的字节数40,而testint(arr)的结果是int*类型的指针的长度4。

    sizeof(int[11])中,很明显数组越界了,但并不会出现运行时错误。原因是:依据我们给出的判断准则,sizeof并没有真正访问arr[11],根据arr的声明,sizeof知道arr[11]是int型的,所以返回int类型的大小。

    至于testint(arr),道理和c中的testchar(dog)相同。

    最后,基于上面的讨论,给出编码准则:

    1.永远不要用sizeof来求字符串长度!它不是干这个活的,所以你也永远不会得到正确答案。

    2.不要自作聪明地用sizeof(arr)/sizeof(arr[0])这样的代码求数组的长度!sizeof也不是干这个活的。如果arr是函数形参,得到的结果将是错误的(除非你在32位系统下恰好声明int arr[1]或者char arr[4]等,但这纯属巧合)。既然是数组,长度自然是已知的,求数组长度这一本身,就是多此一举的愚蠢行为。

    写在后面

    本文的目的,就是使读者对C语言的基础知识——sizeof和strlen有一个本质的认识,同时对与之相关的易错、易混问题有一个正确、清晰的判断。由于在下才疏学浅,错误疏漏之处在所难免,希望广大读者积极批评指正,您的批评指正是在下前进的不竭动力。

  • 相关阅读:
    RequireJS的简单应用
    关于浏览器兼容处理—— 识别IE浏览器
    Div+CSS命名规范
    用CSS开启硬件加速来提高网站性能(转)
    5步解决移动设备上的300ms点击延迟
    全面理解BFC
    纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等)
    Less和Sass编译
    Linux初级知识_03 -- 系统基础命令
    Linux初级知识_02 -- 基础命令
  • 原文地址:https://www.cnblogs.com/zpcdbky/p/5857656.html
Copyright © 2011-2022 走看看