@TOC
本章内容较多,主要是题目的讲解,文字表达啰嗦处请见谅,祝良好的观看体验
可以先在这里尝试所有的题目,如有不懂或不确定的,可按照顺序往下找答案 建议拿个纸笔,先把自己的答案写下来,之后再对答案捏 ↓↓↓↓↓↓↓↓↓↓
一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
字符数组{ 'a','b','c','d','e','f' }->sizeof和strlen
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
字符数组"abcdef"
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
指针接收字符串
char* p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[3]));
原理分析(前提)
指针和数组的概念及补充
- 指针:为了更好的管理内存,给每一块空间都建立了独立的地址,这些地址也被称作为指针;指针 == 地址;
- 数组:能够存放相同类型元素的集合,数组的大小取决于元素个数和元素类型
- 数组名:数组名一般情况下是首元素地址, 只有两种特例: 1、sizeof(数组名):sizeof里面单独放一个数组名是代表的是整个数组 2、&数组名:取地址符取出的是整个数组的地址
- int占用内存的大小是4个字节
- char占用内存的大小是1个字节
- 指针的大小取决于环境,不取决于指针类型,在x86环境下,指针的大小为4个字节,x64环境下指针的大小为8个字节
题目实践(自我检测)
strlen是一个函数,需要你给一个字符指针,然后函数就会以这个指针为起点,不断地向后找'\0',并且给你返回一个从这个指针到'\0'的整形数,记作字符串的长度
sizeof是一个操作符,计算的是操作数在内存中占用的字节大小,根据操作数的类型属性决定
答案本身不重要,重要的是理解数组及指针变化的原理
一维数组
题目:
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
数组名a单独放进sizeof中,数组名a表示整个数组
sizeof得到的值是 数组a的总大小 在内存中占用字节的大小
:4(int)*4(四个元素) = 16
printf("%d\n", sizeof(a + 0));
虽然看似a+0没有什么变化,但是如果数组名a不是单独放到sizeof中
则数组名a表示的是数组首元素的地址(1的地址)
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(*a));
数组名a没有单独放到sizeof中,所以表示的是数组首元素地址
数组首元素地址进行解引用,得到的是数组首元素((int)1)
sizeof得到的值是(int)1在内存中占用字节的大小
:= 4
printf("%d\n", sizeof(a + 1));
数组名a没有单独放到sizeof中,所以表示的是数组首元素地址
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为int*,所以跳过一个整形空间
指针先前指向的是数组首元素地址((int*)1),跳过后,指向数组第二个元素的地址((int *)2)
sizeof得到的值是((int*)2)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(a[1]));
a[1]表示的是数组下标为1的元素((int)2)
sizeof得到的值是((int)2)在内存中占用字节的大小
:= 4
printf("%d\n", sizeof(&a));
&a表示取出了整个数组a的指针(int (*)[4])
sizeof得到的值是(int (*)[4])在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(*&a));
&a表示取出了整个数组a的指针(int (*)[4])
*(&a)表示通过&a解引用找到了a数组
(以上两步亦可理解为*和&可以互相抵消)
以上两步进行后,此时sizeof中的操作数为a
sizeof得到的值是 数组a的总大小 在内存中占用字节的大小
:4(int)*4(四个元素) = 16
printf("%d\n", sizeof(&a + 1));
&a表示取出了整个数组a的指针(int (*)[4])
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为(int (*)[4]),所以跳过一个整形空间
指针先前指向的是数组首元素地址((int*)1),跳过后,指向数组第二个元素的地址((int *)2)
sizeof得到的值是((int *)2)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(&a[0]));
&a[0]表示的是取出a数组中下标为0的元素((int)1)
sizeof得到的值是((int)1)在内存中占用字节的大小
:4
printf("%d\n", sizeof(&a[0] + 1));
&a[0]得到的是a数组首元素的地址((int *)a[0])
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为int*,所以跳过一个整形空间
指针先前指向的是数组首元素地址((int*)1),跳过后,指向数组第二个元素的地址((int *)2)
sizeof得到的值是((int *)2)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
字符数组
char arr[] = { 'a','b','c','d','e','f' };
题目:
strlen
char arr[] = { 'a','b','c','d','e','f' };
(该方式赋值不会自动在字符串末尾添加'\0')
(需要你给一个字符指针,然后函数就会以这个指针为起点,不断地向后找'\0',并且给你返回一个从这个指针到'\0'的整形数,记作字符串的长度)
printf("%d\n", strlen(arr));
arr不是&数组名,也不是sizeof里面单独放一个数组名,所以arr是首元素地址((char*)a)
因为arr数组中没有'\0'作为终止位置,所以strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为随机值
:= 随机值
printf("%d\n", strlen(arr + 0));
arr不是&数组名,也不是sizeof里面单独放一个数组名,所以arr是首元素地址((char*)'a')
地址进行+0的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过零个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char *)'a')
因为arr数组中没有'\0'作为终止位置,所以strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为随机值
:= 随机值
printf("%d\n", strlen(*arr));
arr不是&数组名,也不是sizeof里面单独放一个数组名,所以arr是首元素地址((char*)'a')
*arr表示通过((char*)'a')解引用找到了字符((char)'a')
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'a')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'a')强制类型转化为((char*)97)(因为'a'的ascll码值为97,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)97)不断往后寻找,直到找到了'\0',但是因为((char*)97)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(arr[1]));
arr[1]表示为arr数组里下标为1的元素(((char*)'b'))
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'b')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'b')强制类型转化为((char*)98)(因为'a'的ascll码值为98,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)98)不断往后寻找,直到找到了'\0',但是因为((char*)98)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(&arr));
&arr得到的是整个arr数组的地址
strlen的操作数要求的参数类型为(char*),和现在的操作数(char (*)[6])不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
在地址的角度看,整个数组的地址和数组首元素地址在数值上是一致的
所以,strlen的操作数可看作为数组首元素地址((char*)'a')
因为arr数组中没有'\0'作为终止位置,所以strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为随机值
:= 随机值
printf("%d\n", strlen(&arr[0] + 1));
&arr[0]得到的是arr[0]的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
因为arr数组中没有'\0'作为终止位置,所以strlen将从地址((char *)'b')不断往后寻找,直到找到了'\0',因此返回值为随机值
:= 随机值
sizeof
char arr[] = { 'a','b','c','d','e','f' };
(该方式赋值不会自动在字符串末尾添加'\0')
(计算的是操作数在内存中占用的字节大小,根据操作数的类型属性决定)
printf("%d\n", sizeof(arr));
函数名arr单独放到sizeof,表示的是整个数组
sizeof得到的值是 数组a的总大小 在内存中占用字节的大小
:1(char)* 6(六个元素) = 6
printf("%d\n", sizeof(arr + 0));
数组名arr没有单独放到sizeof,也没有&arr,所以arr表示的是数组首元素地址((char*)'a')
地址进行+0的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'a')
sizeof得到的值是((char*)'a')在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(*arr));
数组名arr没有单独放到sizeof,也没有&arr,所以arr表示的是数组首元素地址((char*)'a')
*arr表示通过数组首元素地址((char*)'a')访问到((char)'a')
sizeof得到的值是((char)'a')在内存中占用字节的大小
:= 1(char类型占一个字节)
printf("%d\n", sizeof(arr[1]));//1
arr[1]表示为数组arr的下标为1的元素((char)'b')
sizeof得到的值是((char)'b')在内存中占用字节的大小
:= 1(char类型占一个字节)
printf("%d\n", sizeof(&arr));
&arr表示取出的是整个数组的地址
sizeof得到的值是(char(*)[6])在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]得到的是数组arr中下表为0的元素的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
sizeof得到的值是((char*)'b')在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(&arr + 1));
- &arr得到的是整个数组的地址(char(*)[6])
- 地址进行+1的操作,跳过多少个字节取决于指针类型
- 当前指针类型为(char(*)[6]),所以跳过一个字符数组的空间(char [6])
- 指针先前指向的是整个数组的地址p1(char(*)[6]),跳过一个字符数组空间后,指向p2
- sizeof得到的值是((char(*)[6]))在内存中占用字节的大小
- 地址的大小是4/8个字节
- := 4/8
char arr[] = "abcdef";
题目:
strlen
char arr[] = "abcdef";
(该方式赋值会自动在字符串末尾添加'\0')
(相当于{'a', 'b', 'c', 'd', 'e', 'f', '\0'})
(需要你给一个字符指针,然后函数就会以这个指针为起点,不断地向后找'\0',并且给你返回一个从这个指针到'\0'的整形数,记作字符串的长度)
printf("%d\n", strlen(arr));
arr不是单独放在sizeof中,也不是&arr,表示的是首元素的地址((char *)'a')
strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为6
:= 6
printf("%d\n", strlen(arr + 0));
arr不是单独放在sizeof中,也不是&arr,表示的是首元素的地址((char *)'a')
地址进行+0的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'a')
strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为6
:= 6
printf("%d\n", strlen(*arr));
arr不是单独放在sizeof中,也不是&arr,表示的是首元素的地址((char *)'a')
*arr表示通过数组首元素地址((char*)'a')访问到((char)'a')
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'a')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'a')强制类型转化为((char*)97)(因为'a'的ascll码值为97,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)97)不断往后寻找,直到找到了'\0',但是因为((char*)97)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(arr[1]));
arr[1]表示的是数组arr中下标为1的元素((char)'b')
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'b')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'b')强制类型转化为((char*)98)(因为'b'的ascll码值为98,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)98)不断往后寻找,直到找到了'\0',但是因为((char*)98)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(&arr[0] + 1));
arr[0]表示的是数组arr中下标为1的元素((char)'a')
&arr[0]得到的是数组arr中下标为1的元素((char)'a')的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
strlen将从地址((char *)'b')不断往后寻找,直到找到了'\0',因此返回值为5
:= 5
printf("%d\n", strlen(&arr));
- &arr表示的是取出整个数组的地址(char(*)[7])
- (↑↑↑相比于{ 'a','b','c','d','e','f' }的形式, "abcdef"形式因为会自动补'\0'而{ 'a','b','c','d','e','f' }的形式不会自动补'\0',所以数组大小要比第一种大一)
- strlen的操作数要求的参数类型为(char*),和现在的操作数(char()[7])不匹配 为了运行下去,strlen函数会将操作数的类型强制转化成(char)
- 由于整个数组的地址在数值上与数组首元素地址一致,且strlen只需要得到(char*)的地址,所以可以将&arr的地址值看做首元素地址((char *)'a')
- strlen将从地址((char *)'a')不断往后寻找,直到找到了'\0',因此返回值为6
printf("%d\n", strlen(&arr + 1));
- &arr得到的是整个数组的地址(char(*)[7])
- 地址进行+1的操作,跳过多少个字节取决于指针类型
- 当前指针类型为(char(*)[7]),所以跳过一个字符数组空间
- 指针先前指向的是数组首元素地址p1,跳过后,指向数组第二个元素的地址p2
- strlen将从地址p2不断往后寻找,直到找到了'\0',由于在后面的内存中不知什么时候才能找到'\0',因此返回值为随机值
- := 随机值
sizeof
char arr[] = "abcdef";
(该方式赋值会自动在字符串末尾添加'\0')
(相当于{'a', 'b', 'c', 'd', 'e', 'f', '\0'})
(计算的是操作数在内存中占用的字节大小,根据操作数的类型属性决定)
p.s:'\0'也算一个字符
printf("%d\n", sizeof(arr));
arr单独放到sizeof中表示的是整个数组
sizeof得到的值是 数组arr的总大小 在内存中占用字节的大小
:1(char)* 7(七个元素) = 7
printf("%d\n", sizeof(arr + 0));
arr不是单独放到sizeof中,也不是&arr,所以表示的是数组首元素的地址((char*)'a')
地址进行+0的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过零个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'a')
sizeof得到的值是(char*)'a')在内存中占用字节的大小
=4/8
printf("%d\n", sizeof(*arr));
*arr是数组首元素((char)'a')
sizeof得到的值是(char)'a')在内存中占用字节的大小
=1
printf("%d\n", sizeof(arr[1]));
arr[1]表示的是数组中下标为1的元素((char)'b')
sizeof得到的值是(char)'b')在内存中占用字节的大小
=1
printf("%d\n", sizeof(&arr));
&arr表示的是取出了整个数组的地址(char(*)[7])
sizeof得到的值是(char(*)[7])在内存中占用字节的大小
=4/8
printf("%d\n", sizeof(&arr + 1));
&arr表示的是取出了整个数组的地址(char(*)[7])
地址进行+0的操作,跳过多少个字节取决于指针类型
当前指针类型为(char(*)[7]),所以跳过七个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'a'+7)
sizeof得到的值是((char*)'a'+7)在内存中占用字节的大小
=4/8
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]取出的是数组首元素的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为(char),所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
sizeof得到的值是((char*)'b')在内存中占用字节的大小
=4/8
指针接收字符串
char* p = "abcdef";
(该方式赋值会自动在字符串末尾添加'\0')
(相当于{'a', 'b', 'c', 'd', 'e', 'f', '\0'})
printf("%d\n", strlen(p));
p没有单独放到sizeof内部,也没有&,表示的是数组首元素的地址((char*)'a')
strlen计算的是从地址处((char*)'a')不断往后找,直到找到了'\0'后的长度
= 6
printf("%d\n", strlen(p + 1));
p没有单独放到sizeof内部,也没有&,表示的是数组首元素的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
strlen计算的是从地址处((char*)'b')不断往后找,直到找到了'\0'后的长度
=5
printf("%d\n", strlen(*p));
p表示的是字符串首元素的地址((char*)'a')
*p表示向地址((char*)'a')解引用得到((char)'a')
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'a')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'a')强制类型转化为((char*)97)(因为'a'的ascll码值为97,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)97)不断往后寻找,直到找到了'\0',但是因为((char*)97)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(p[0]));
p[0]表示的是该字符串的第一个元素((char)'a')
strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'a')不匹配
为了运行下去,strlen函数会将操作数的类型强制转化成(char*)
((char)'a')强制类型转化为((char*)97)(因为'a'的ascll码值为97,地址的形式是以数字的方式呈现的)
strlen将从地址((char*)97)不断往后寻找,直到找到了'\0',但是因为((char*)97)不属于我们创造的地址,访问方式为非法访问
编译器将会报错
printf("%d\n", strlen(&p[0] + 1));
p[0]表示的是该字符串的第一个元素((char)'a')
&p[0]表示的是取出字符串的第一个元素((char)'a')的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
strlen计算的是从地址处((char*)'b')不断往后找,直到找到了'\0'后的长度
=5
printf("%d\n", sizeof(p));
p是一个字符指针
sizeof得到的值是(char(*))在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(p + 1));
p是一个字符指针
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
sizeof得到的值是(char(*))在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(*p));
p表示的是字符串首元素的地址((char*)'a')
*p表示向地址((char*)'a')解引用得到((char)'a')
sizeof得到的值是(char)在内存中占用字节的大小
=1
printf("%d\n", sizeof(p[0]));
p[0]表示的是该字符串的第一个元素((char)'a')
sizeof得到的值是(char)在内存中占用字节的大小
=1
printf("%d\n", sizeof(&p));
p是一个字符指针
&p表示的是取出这个字符指针的指针(应当用二级指针接收)
sizeof得到的值是(char**)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(&p + 1));
p是一个字符指针
&p表示的是取出这个字符指针的指针(二级指针)
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char**,所以跳过一个字符指针的空间(四个字节)
指针先前指向的是数组首元素地址((char**)&p),跳过后,指向数组第二个元素的地址((char**)&p+4)
sizeof得到的值是(char**)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(&p[0] + 1));
p[0]表示的是该字符串的第一个元素((char)'a')
&p[0]表示的是取出字符串的第一个元素((char)'a')的地址((char*)'a')
地址进行+1的操作,跳过多少个字节取决于指针类型
当前指针类型为char*,所以跳过一个字符空间
指针先前指向的是数组首元素地址((char*)'a'),跳过后,指向数组第二个元素的地址((char*)'b')
sizeof得到的值是(char*)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
特殊案例
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
- &p表示的是取出这个字符指针的指针(应当用二级指针接收)
- 地址进行+1的操作,跳过多少个字节取决于指针类型
- 当前指针类型为char**,所以跳过一个字符指针的空间(四个字节)
- 指针先前指向的是数组首元素地址((char**)&p),跳过后,指向数组第二个元素的地址((char**)&p+4)
由上图,可得出以下结论
- p是一个字符指针,&p得到的一个字符指针的地址,用二级指针来接收
- 蓝色:p指向的类型是(char),解引用和+1或-1操作时,访问的是一个字节的空间
- 蓝色:p指向的类型是(char),解引用和+1或-1操作时,访问的是一个字节的空间
- 橙色:&p指向的类型是(char*),解引用和+1或-1操作时,访问的是四个字节的空间
- 蓝色:strlen(p)和strlen(p+1)存在紧密联系,在值上strlen(p+1)比strlen(p)小1
- 绿色:strlen(&p)和strlen(&p+1)在值上不存在紧密联系,原因如下
(strlen的操作数要求的参数类型为(char*),和现在的操作数((char)'a')不匹配为了运行下去,strlen函数会将操作数的类型强制转化成(char*)) 当前,(&p)和(&p+1)强制转化成char*,也就代表着它们每次只能访问1个字节 &p和&p+1之间存在四个字节的空间(绿色箭头指向的位置) 假设编号3的位置是'\0',则strlen(&p)= 3,而strlen(&p+1)因为不确定'\0'的位置而为随机值 只有在&p和&p+1之间存在的四个字节空间内没有'\0'的情况下,strlen(&p)才等于strlen(&p+1)+4
二维数组
题目:int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 }; 做题的前提:
- 在内存中的存储:
2. 二维数组可以理解为是一维数组的数组,a[0]表示的是第一行的数组名。是数组a的第一个元素,a[1]表示的是第二行的数组名,是数组a的第二个元素;如果不是&a或者sizeof中单独放a,表示的是首元素的地址,即&a[0]
int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
printf("%d\n", sizeof(a));
a这个二维数组的数组名单独放在sizeof内部,a表示的是整个数组
sizeof得到的值是 数组a的总大小 在内存中占用字节的大小
:4(int)* 12(十二个元素) = 48
printf("%d\n", sizeof(a[0][0]));
a[0][0]表示第一行第一个元素
4个字节
printf("%d\n", sizeof(a[0]));//16
a[0] 第一行的数组名,这时数组名单独放在sizeof内部了
计算的是数组(int [4])的大小,单位是字节,16
printf("%d\n", sizeof(a[0] + 1));//4
a[0]不是单独放在sizeof内部,a[0]表示的首元素的地址,即第一行第一个元素的地址,(可理解为&a[0][0])
a[0] + 1 是第一行第2个元素的地址 &a[0][1]
sizeof得到的值是(int*)在内存中占用字节的大小
地址的大小是4/8个字节
:= 4/8
printf("%d\n", sizeof(*(a[0] + 1)));
a[0]不是单独放在sizeof内部,a[0]表示的首元素的地址,即第一行第一个元素的地址,(可理解为&a[0][0])
a[0] + 1 是第一行第2个元素的地址 &a[0][1]
*(a[0] + 1)表示通过(a[0] + 1)解引用找到a[0][1]
printf("%d\n", sizeof(a + 1));
a作为二维数组的数组名并非单独放在sizeof内部,所以表示首元素的地址
二维数组的首元素是第一行,这里的a就是第一行的地址(int (*)[4])
a+1是跳过第一行,指向了第二行
sizeof得到的值是(int (*)[4])在内存中占用字节的大小
地址的大小是4/8个字节
printf("%d\n", sizeof(*(a + 1)));
a作为二维数组的数组名并非单独放在sizeof内部,所以表示首元素的地址
二维数组的首元素是第一行,这里的a就是第一行的地址(int (*)[4])
a+1是跳过第一行,指向了第二行
对第二行的地址进行解引用,得到的是第二行的数组
sizeof计算的是数组(int [4])的大小,单位是字节,16
printf("%d\n", sizeof(&a[0] + 1));
&a[0]是第一行的地址
&a[0]+1是第二行的地址
sizeof得到的值是(int (*)[4])在内存中占用字节的大小
地址的大小是4/8个字节
printf("%d\n", sizeof(*(&a[0] + 1)));
&a[0]+1是第二行的地址
对第二行的地址进行解引用得到第二行的数组a[1]
sizeof计算的是数组(int [4])的大小,单位是字节,16
printf("%d\n", sizeof(*a));
a不是单独放到sizeof中,表示的是数组首元素地址(int *[4])
对数组首元素地址(int *[4])解引用得到的是第一行的数组
sizeof计算的是数组(int [4])的大小,单位是字节,16
特殊案例
printf("%d\n", sizeof(a[3]));
- a[3]得到的是数组a的第四行的数组名,类型还是(int [4])
- 【因为这个a[3]是源于a数组的】
- sizeof计算的是数组(int [4])的大小,单位是字节,16
这里看似是越界访问了,按道理来说应该会报警告
但是这个和sizeof的原理有关,sizeof内部的表达式不会真的去计算,只需要通过类型就可以得出结果,计算的步骤反而冗余了,不存在计算就不存在越界访问
sizeof科普:
- 任何一个值或者表达式都存在两个属性,一是值属性,二是类型属性
例:int a = 7; a+3 值属性:10 类型属性:int
- 代码写出来之后,要进行编译、链接、运行的过程,sizeof已经在编译过程中根据类型属性得到了值,所以值就不会再计算了
int a = 5;
short s = 11;
printf("%d\n", sizeof(s = a + 2));//2
printf("%d\n", s);//11
以上就是关于数组和指针运用理解的练习,如果有什么地方不足,欢迎评论区或私信如果这篇文章对你有用的话,希望可以得到一个免费的赞,拜托了捏