当前位置 : 主页 > 编程语言 > c语言 >

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

来源:互联网 收集:自由互联 发布时间:2023-09-06
@TOC 本章内容较多,主要是题目的讲解,文字表达啰嗦处请见谅,祝良好的观看体验 可以先在这里尝试所有的题目,如有不懂或不确定的,可按照顺序往下找答案建议拿个纸笔,先把自

@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]),所以跳过一个字符数组空间
  • 学习效果检验:(超详细)深度理解指针和数组_操作数_02

  • 指针先前指向的是数组首元素地址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)

学习效果检验:(超详细)深度理解指针和数组_操作数_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 }; 做题的前提:

  1. 在内存中的存储:

学习效果检验:(超详细)深度理解指针和数组_数组_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科普:

  1. 任何一个值或者表达式都存在两个属性,一是值属性,二是类型属性

例:int a = 7; a+3 值属性:10 类型属性:int

  1. 代码写出来之后,要进行编译、链接、运行的过程,sizeof已经在编译过程中根据类型属性得到了值,所以值就不会再计算了
int a = 5;
	short s = 11;
	printf("%d\n", sizeof(s = a + 2));//2
	printf("%d\n", s);//11

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

上一篇:c++核心编程—引用
下一篇:没有了
网友评论