sizeof不是函数,而是一个操作符,sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。 sizeof 只关注占⽤内存空间的大小,不在乎内存中存放什么数据。
sizeof()的操作数可以是一个变量也可以是一个数据类型,需要注意的是当操作数是变量时()可以省去,当操作数是数据类型时()不可以省去。
#inculde
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));
return 0;
}
strlen 是C语⾔库函数,使用时要包含头文件string.h,功能是求字符串长度。函数原型如下:
size_t strlen ( const char * str ); 返回值size_t类型实质上就是无符号整型,打印时的形式的zd%,参数是一个字符指针,const修饰的是*str,使得不能通过指针改变原字符串的内容。本质是从该字符指针指向的位置/字符开始计数,直到遇到\0(\0的ASCII码是0),停止计数,返回字符不是\0的个数,strlen要遇到\0才停止计算,故strlen可能出现越界查找的问题。
size_t my_strlen(const char* p)
{
int count = 0;
while(*p) //*p != '\0'
{
count++;
p++;
}
return count;
}
#include
int main()
{
char arr1[3] = {'a', 'b', 'c'};
char arr2[] = "abc";
printf("%zd\n", strlen(arr1));//随机数
printf("%zd\n", strlen(arr2));//3
printf("%zd\n", sizeof(arr1));//3
printf("%zd\n", sizeof(arr1));//4
return 0;
}
数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //4*4=16 szieof(数组名)特殊用法表示求整个数组的大小
printf("%d\n",sizeof(a+0)); //4/8 数组名a表示首元素地址,即元素1的地址
printf("%d\n",sizeof(*a)); //4 *a == *(a+0) == a[0] == 1
printf("%d\n",sizeof(a+1)); //4/8 数组名a表示首元素地址,a+1是a[1]的地址
printf("%d\n",sizeof(a[1])); //4 a[1] == 2
printf("%d\n",sizeof(&a)); //4/8 &数组名,表示整个数组的地址
printf("%d\n",sizeof(*&a)); //16 1.*和&可以相互抵消,sizeof(*&a) == sizeof(a)
//2.&数组名,表示整个数组的地址,解引用后就是整个数组
printf("%d\n",sizeof(&a+1)); //4/8 &数组名,表示整个数组的地址,&a+1跳过整个数组
printf("%d\n",sizeof(&a[0])); //4/8 数组第一个元素的地址
printf("%d\n",sizeof(&a[0]+1));//4/8 数组第二个元素的地址
注意点:
地址是4/8个字节的原因,地址长度由当前系统决定,当编译器选择32位机(x86),数据的地址有32位,32/8(一个字节的位数)=4(Byte)。当编译器选择64位机(x64),数据的地址有64位,64/8(一个字节的位数)=8(Byte)
注意不要混淆
32位机的%p打印出来地址是0000 00ff:%p是以16进制打印地址的,32/4(二进制转十六进制1111=f)=8位,64位机的%p打印出来地址是0000 0000 0000 00ff:64/4(二进制转十六进制1111=f)=16位
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr)); //6 sizeof(数组名),计算整个数组的大小
printf("%d\n", sizeof(arr+0)); //4/8 数组名arr表首元素地址,arr+0还是首元素的地址
printf("%d\n", sizeof(*arr)); //1 数组名arr表首元素地址,*arr == 'a'
printf("%d\n", sizeof(arr[1])); //1 arr[1] == 'b'
printf("%d\n", sizeof(&arr)); //4/8 &arr表示整个数组的地址
printf("%d\n", sizeof(&arr+1)); //4/8 &arr+1表示跳过整个字符数组
printf("%d\n", sizeof(&arr[0]+1)); //4/8 &arr[0]+1表示&arr[1]即符号'b'的地址
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr)); //随机值 数组名arr表示首元素地址,直到遇到\0停止计数
printf("%d\n", strlen(arr+0)); //随机值 数组名arr表示首元素地址,arr+0还是首元素地址
printf("%d\n", strlen(*arr)); //err *arr == 'a','a'的ASCII码是97,取的地址是97
printf("%d\n", strlen(arr[1])); //err arr[1] == 'b','b'的ASCII码是98,取的地址是98
printf("%d\n", strlen(&arr)); //随机值 strlen函数的参数类型是char*,而&arr表示整个数
//组的地址,指针类型是char(*)[6],是一个数组的指针,所以
//会报警告但不会报err,结果与strlen(arr)的结果保持一致
printf("%d\n", strlen(&arr+1)); //随机值-6 &arr+1跳过整个数组的大小
printf("%d\n", strlen(&arr[0]+1)); //随机值-1 &arr[0]+1表示'b'的地址
char arr[] = "abcdef"; //等价于char arr[] = {'a','b','c','d','e','f','\0'};
printf("%d\n", sizeof(arr)); //7 sizeof(数组名)特殊用法求整个数组的大小
printf("%d\n", sizeof(arr+0)); //4/8 数组名arr表示首元素地址,arr+0仍表示首元素地址
printf("%d\n", sizeof(*arr)); //1 *arr == 'a'
printf("%d\n", sizeof(arr[1])); //1 arr[1] == 'b'
printf("%d\n", sizeof(&arr)); //4/8 &arr表示整个数组的大小
printf("%d\n", sizeof(&arr+1)); //4/8 &arr+1表示跳过整个数组的大小
printf("%d\n", sizeof(&arr[0]+1));//4/8 &arr[0]+1 == &arr[1],字符'b'的地址
char arr[] = "abcdef";
printf("%d\n", strlen(arr)); //6 数组名arr表示首元素的地址
printf("%d\n", strlen(arr+0)); //6 arr+0仍表示首元素的地址
printf("%d\n", strlen(*arr)); //err *arr == 'a' ASCII码表示97
printf("%d\n", strlen(arr[1])); //err arr[1] == 'b' ASCII码表示98
printf("%d\n", strlen(&arr)); //6 &arr表示整个数组的地址
printf("%d\n", strlen(&arr+1)); //随机值 &arr+1跳过整个数组
printf("%d\n", strlen(&arr[0]+1));//5 &arr[0]+1 ==&arr[1]
char *p = "abcdef";
printf("%d\n", sizeof(p)); //4/8 p是指向字符串第一个字符a的指针
printf("%d\n", sizeof(p+1)); //4/8 p+1指向字符串第二个字符b的指针
printf("%d\n", sizeof(*p)); //1 *p == 'a',表示一个字符
printf("%d\n", sizeof(p[0])); //1 p[0] == *(p+0) == 'a'
printf("%d\n", sizeof(&p)); //4/8 &p表示指针的地址,是二级指针,类型是char* *:第二个*表
//示是一个指针,第二个*表示该指针指向对象的类型是char*,即+-
//该指针时跳过的是一个char*类型(地址,4/8个字节)
printf("%d\n", sizeof(&p+1)); //4/8
printf("%d\n", sizeof(&p[0]+1));//4/8 &p[0]+1 == &p[1]即字符'b'的地址
跳过一个char*变量,char*是一个指向char类型的指针/地址,大小是4/8个字节,则跳过一个char*变量就是跳过4/8个字节。
char *p = "abcdef";
printf("%d\n", strlen(p)); //6 指针p指向字符'a'
printf("%d\n", strlen(p+1)); //5 指针p+1指向字符'b'
printf("%d\n", strlen(*p)); //err *p == 'a',ASCII码值是97
printf("%d\n", strlen(p[0])); //err p[0] == *p == 'a',ASCII码值是97
printf("%d\n", strlen(&p)); //随机值 指针p的地址,二级指针
printf("%d\n", strlen(&p+1)); //随机值 &p+1跳过一个char*类型
printf("%d\n", strlen(&p[0]+1)); //5 &p[0]+1 == &p[1]即字符'b'的地址
最后一个strlen(&p[0]+1) ,指针p优先与[]结合,p[0] == *p == 'a' ,再与&结合,表示第一个元素的地址,+1表示第二个元素的地址,下面详见操作符的优先级。
2.3 ⼆维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a)); //3*4*4=48 sizeof(数组名),计算整个二维数组的有多少个字节
printf("%d\n",sizeof(a[0][0])); //4 a[0][0]表示整个数组的第一个元素
printf("%d\n",sizeof(a[0])); //4*4=16 a[0]表示二维数组第1行的数组名,sizeof(数组名)特
//殊用法,表达整个数组的大小
printf("%d\n",sizeof(a[0]+1)); //4/8 数组名a[0]表示数组首元素的地址,即&a[0][0],+1是
//a[0][1]的地址即&a[0][1]
printf("%d\n",sizeof(*(a[0]+1)));//4 等价于*&a[0][1] == a[0][1] == 0
printf("%d\n",sizeof(a+1)); //4/8 二维数组数组名a表示首元素地址,二维数组的首元素是第
//一行,故a+1 == &a[0]+1,表示第二行的地址即&a[1]
printf("%d\n",sizeof(*(a+1))); //4*4=16 等价于*&a[1] == a[1],求第二行的总字节数
printf("%d\n",sizeof(&a[0]+1)); //4/8 表示第二行的地址即&a[1]
printf("%d\n",sizeof(*(&a[0]+1)));//4*4=16 等价于*&a[1] == a[1],求第二行的总字节数
printf("%d\n",sizeof(*a)); //4*4=16 二维数组数组名a表示首元素地址,二维数组的首元素
//是第一行,故*a == *&a[0] == a[0],求第一行的总字节数
printf("%d\n",sizeof(a[3])); //4*4=16 不会报错,sizeof()只是求()里的变量类型有多少个
//字节,本质相当于求sizeof(a[0]),即求一行的字节个数
#include
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?2 5
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);//注意这里指针p强转为了为符号长整型,相当于转换成了
//地址(相当于0000 00ff),+1就是普通的整数+1
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
假设的原因是x64环境下结构体的大小就不是20个字节了
#include
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]); //1
return 0;
}
注意点:逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。
//假设环境是x86环境,程序输出的结果是啥?
#include
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
} //答案:FFFF FFFC 4
限制环境是因为想要一个唯一的答案,32位和64位的地址长度不同。
#include
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10 5
return 0;
}
详解:int *ptr2 = (int *)(*(aa + 1));
二维数组数组名aa表首元素的地址,二维数组的首元素是第一行,则aa是第一行的地址,aa+1是第二行的地址及&aa[1],*(aa+1) == *&aa[1] == aa[1](第二行的数组名),数组名aa[1]表示首元素aa[1][0]的地址.*(aa + 1)本身就是int*类型,这里的强转如同虚设。
#include
int main()
{
char *a[] = {"work","at","alibaba"};//[]的优先级比*高,故a先与[]结合,a是一个指针数组,指
//针类型是char*
char**pa = a; //两级指针,数组名a表示首元素的地址,pa指向a[0]
pa++; //pa指向a[1]
printf("%s\n", *pa); //*pa == a[1] == 指向字符'a'的char*指针
return 0;
}
//答案:at
#include
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}
//POINT
//ER
//ST
//EW
优先级:++ > * >+