学习效果检验:(超详细)深度理解指针和数组 您所在的位置:网站首页 指针指向二维数组的几种方法图解说明 学习效果检验:(超详细)深度理解指针和数组

学习效果检验:(超详细)深度理解指针和数组

2023-05-02 03:05| 来源: 网络整理| 查看: 265

@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' };

题目:

strlenchar 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',因此返回值为随机值 := 随机值sizeofchar 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/8printf("%d\n", sizeof(&arr + 1));&arr得到的是整个数组的地址(char(*)[6])地址进行+1的操作,跳过多少个字节取决于指针类型当前指针类型为(char(*)[6]),所以跳过一个字符数组的空间(char [6])

学习效果检验:(超详细)深度理解指针和数组_数组

指针先前指向的是整个数组的地址p1(char(*)[6]),跳过一个字符数组空间后,指向p2sizeof得到的值是((char(*)[6]))在内存中占用字节的大小地址的大小是4/8个字节:= 4/8char arr[] = "abcdef";

题目:

strlenchar 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 := 5printf("%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',因此返回值为6printf("%d\n", strlen(&arr + 1));&arr得到的是整个数组的地址(char(*)[7])地址进行+1的操作,跳过多少个字节取决于指针类型当前指针类型为(char(*)[7]),所以跳过一个字符数组空间

学习效果检验:(超详细)深度理解指针和数组_数组名_02

指针先前指向的是数组首元素地址p1,跳过后,指向数组第二个元素的地址p2strlen将从地址p2不断往后寻找,直到找到了'\0',由于在后面的内存中不知什么时候才能找到'\0',因此返回值为随机值:= 随机值sizeofchar 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)

学习效果检验:(超详细)深度理解指针和数组_数组_03

由上图,可得出以下结论

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 }; 做题的前提:

在内存中的存储:

学习效果检验:(超详细)深度理解指针和数组_数组名_04

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

以上就是关于数组和指针运用理解的练习,如果有什么地方不足,欢迎评论区或私信如果这篇文章对你有用的话,希望可以得到一个免费的赞,拜托了捏



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有