strlen和sizeof相关计算
Suzhou 48 1

::: warning strlen只能计算字符数组的长度。 sizeof可以计算任意类型大小。 :::

一维数组

数组名是首元素地址。 两个例外: 1. sizeof(数组名),数组名表示整个数组。 2. &数组名,数组名表示整个数组。

int main()
{
    int a[] = { 1,2,3,4 };
    printf("%d\n", sizeof(a));  //16
    printf("%d\n", sizeof(a + 0));  //4/8。a+0不是数组名,此时a表示首元素地址
    printf("%d\n", sizeof(*a));  //4。a表示首元素地址,*a表示首元素
    printf("%d\n", sizeof(a + 1));  //4/8。和a+0思路一致
    printf("%d\n", sizeof(a[1]));  //4/8。第二个元素大小。
    printf("%d\n", sizeof(&a));  //4/8。&a取出的是数组a地址,指针的大小是4/8字节
    printf("%d\n", sizeof(*&a));  //16。&a取出数组a地址,数组地址解引用访问整个数组
    printf("%d\n", sizeof(&a + 1));  //4/8。数组a的地址+1,跳过数组a,仍表示地址
    printf("%d\n", sizeof(&a[0]));  //4/8。相当于&(a[0]),取出首元素地址
    printf("%d\n", sizeof(&a[0] + 1));  //4/8。相当于(&a[0])+1,取出第二个元素地址
    return 0;
}

字符数组
int main()
{
    char arr[] = { 'a','b', 'c', 'd ', 'e ', 'f' };
    printf("%d\n", sizeof(arr));  //6
    printf("%d\n", sizeof(arr + 0));  //4
    printf("%d\n", sizeof(*arr));  //1
    printf("%d\n", sizeof(arr[1]));  //1
    printf("%d\n", sizeof(&arr));  //4/8
    printf("%d\n", sizeof(&arr + 1));  //4/8
    printf("%d\n", sizeof(&arr[0] + 1));  //4/8
    return 0;
}

strlen计算字符长度时一定要找到\0才能停止。

int main()
{
    char arr[] = { 'a', 'b','c ', 'd', 'e', 'f'};
    printf("%d\n", strlen(arr));  //随机值
    //arr是首元素地址开始向后计算
    printf("%d\n", strlen(arr + 0));  //随机值
    //等同于strlen(arr)
    printf("%d\n", strlen(*arr));   //error
    //strlen的参数是地址,*arr是首元素,相当于传入'a'的ASCII码97,
    //strlen会把97当成起始地址向后计算字符,非法访问内存
    printf("%d\n", strlen(arr[1]));  //error
    //相当于传入'b'的ASCII码98,非法访问内存
    printf("%d\n", strlen(&arr));  //随机值
    //&arr取得数组(首元素)地址,等同于strlen(arr)
    printf("%d\n", strlen(&arr + 1));  //随机值
    //&arr首元素地址+1,跳过整个数组
    printf("%d\n", strlen(&arr[0] + 1));  //随机值
    //&arr首元素地址+1,从第二个元素开始
    return 0;
}

::: warning char arr1[] = { 1,2,3,4,5,6 }; arr1中元素为1,2,3,4,5,6。 char arr2[] = "123456"; arr2中元素为1,2,3,4,5,6,\0。 :::


int main()
{
    char arr[] = "abcdef";
    printf("%d\n", sizeof(arr));  //7
    printf("%d\n", sizeof(arr + 0));  //8
    printf("%d\n", sizeof(*arr));  //1
    printf("%d\n", sizeof(arr[1]));  //1
    printf("%d\n", sizeof(&arr));  //4/8
    printf("%d\n", sizeof(&arr + 1));  //4/8
    printf("%d\n", sizeof(&arr[0] + 1));  //4/8
    return 0;
}

#include <string.h>
int main()
{
    char arr[] = "abcdef";
    printf("%d\n", strlen(arr));  //6。arr表示首元素地址
    printf("%d\n", strlen(arr + 0));  //6。等同于strlen(arr)
    //printf("%d\n", strlen(*arr));   //error
    //strlen的参数是地址,*arr是首元素,相当于传入'a'的ASCII码97,
    //strlen会把97当成起始地址向后计算字符,非法访问内存
    //printf("%d\n", strlen(arr[1]));  //error
    printf("%d\n", strlen(&arr));  //6。&arr取得数组地址,等同于strlen(arr[0])
    //printf("%d\n", strlen(&arr + 1));  //error。&arr取得数组地址,+1跳过整个数组
    printf("%d\n", strlen(&arr[0] + 1));  //5。从第二个字符向后计算
    return 0;
}

上述代码第11行中,arr是数组,&arr的取出数组的地址,应该存放在数组指针char( * p)[7]中,类型是char( * )[7],strlen的类型是const char*,类型不同所以sizeof(&arr)运行报警告如下: strlen和sizeof相关计算


int main()
{
    char* p = "abcdef";  //p是大小为4字节的指针
    //将常量字符串abcdef的首字符a的地址放进p中
    printf("%d\n", sizeof(p));  //4/8
    //计算指针变量p的大小
    printf("%d\n", sizeof(p + 1));  //4/8
    //p中存放a的地址,p+1指向b的地址
    printf("%d\n", sizeof(*p));  //1
    //p是a的地址,*p是'a'
    printf("%d\n", sizeof(p[0]));  //1
    printf("%d\n", sizeof(&p));  //4/8。
    //&p表示p的地址
    printf("%d\n", sizeof(&p + 1));  //4/8
    //*p的地址+1跳过*p,仍是地址
    printf("%d\n", sizeof(&p[0] + 1));  //4/8
    //p[0]是a的地址,解引用后+1是b的地址
    return 0;
}

::: tip 上述代码第11行,当int arr[10]; arr[0] == * (arr + 0); 所以p[0] == * (p + 0) == 'a'; :::


int main()
{
    char* p = "abcdef";  //p是大小为4字节的指针
    printf("%d\n", strlen(p));  //6
    //p存储a的地址,即strlen(p)是从a开始向后计算直到\0
    printf("%d\n", strlen(p + 1));  //5
    //p存储a的地址,p+1是从b开始向后计算直到\0
    printf("%d\n", strlen(*p));   //error
    //*p是把a当作地址传给strlen
    printf("%d\n", strlen(p[0]));   //error
    //*p等同于p[0]
    printf("%d\n", strlen(&p));   //随机值
    //p是存放a的地址的单独的内存空间,取出p的地址向后计算长度,直到遇到\0
    printf("%d\n", strlen(&p + 1));   //随机值
    //p是放a的地址的单独的内存空间,+1跳过p,取出p的地址向后计算长度,直到遇到\0
    printf("%d\n", strlen(&p[0] + 1));  //5
    //p[0]是a,&a取到a的地址后+1,是从b开始计算
    return 0;
}

二维数组
int main()
{
    int a[2][3] = { 0 };
    //printf("%p\n", &a[0][0]);
    //printf("%p\n", a[0] + 1);
    //printf("%p\n", &a[0]+1);
    printf("%d\n", sizeof(a));  //24。计算数组总大小:2*3*4
    printf("%d\n", sizeof(a[0][0]));  //4。第1行第1列的一个元素大小
    printf("%d\n", sizeof(a[0]));  //12。表示二维数组第一行元素
    printf("%d\n", sizeof(a[0] + 1));  //4/8。表示第一行第二个元素地址
    //a[0]没有单独放在sizeof内,表示二维数组第1行第1个元素地址
    printf("%d\n", sizeof(*(a[0] + 1)));  //4。第1行第2个元素大小
    printf("%d\n", sizeof(a + 1));  //4/8。二维数组第2行地址
    //二维数组的首元素表示第1行,即二维数组的数组名表示第1行的地址
    printf("%d\n", sizeof(*(a + 1)));  //12。*(a + 1)等同于a[1]
    //a+1是第2行地址,解引用找到第2行元素,即第2行的数组名,sizeof(数组名)是数组大小
    printf("%d\n", sizeof(&a[0] + 1));   //4/8。&a[0]是第1行地址,+1跳到第2行
    printf("%d\n", sizeof(*(&a[0] + 1)));   //12。&a[0] + 1是第2行地址,解引用得到第二行
    printf("%d\n", sizeof(*a));  //12。a是首元素地址即第一行地址,解引用得到第一行
    printf("%d\n", sizeof(a[3]));  //12。第四行地址
    return 0;
}

上述代码中第6行,a[0]是数组名,sizeof+数组名是计算整个数组的大小即二维数组该行的大小。 ::: warning 在二维数组中,每一行的元素都是arr[行数][i],如下: |arr[0][0]|arr[0][1]|arr[0][2]| |-|-|-| |arr[1][0]|arr[1][1]|arr[1][2]| 就可以把a[0]理解成第一行元素组成的数组的数组名,a[1]理解成第二行元素组成的数组的数组名,数组名+i访问下标元素。 ::: ::: tip 上述代码第6、第7行:

int main()
{
    int a[2][3] = { 0 };
    printf("%p\n", &a[0][0]);
    printf("%p\n", a[0] + 1);
    printf("%p\n", &a[0]+1);
    return 0;
}
0000004B094FFC78
0000004B094FFC7C
0000004B094FFC84

对第5、第6行结果的对比,表示a[0]+1是第1行第2列元素。 对第6、第7行结果的对比,表示&a[0]是第1行元素的地址。 ::: 上述代码第13行,当二维数组的数组名没有单独出现在sizeof或&后时,将二维数组当作一维数组,二维数组的每一行当作一维数组的每个元素。二维数组的首元素表示第一行,即二维数组的数组名表示第一行的地址 上述代码第20行,sizeof计算a[3]超出数组范围,但sizeof不访问数组,只是列出第4行的数组名,即使数组不存在,sizeof也会根据数组类型计算第四行元素的大小。 ::: warning sizeof内部表达式不参与真实运算。 :::

评论区

索引目录