C语言复习—指针,数组,sizeof与strlen区别总结

前段时间主要学习了一些关于指针方面的知识,结合以前碰到的一些问题,在这里总结一下,便于以后的学习。

一 指针中易混淆的问题

1)关于int * const a;和 int const * a;的区别:

前面一个学名叫**指针常量**,表示整形指针a指向固定的地址,不能对a的值进行加减、赋值操作。但是可以对整形指针a的解引用(*a)进行赋值等操作;
后面一个学名叫**常量指针**,表示整形指针a的解引用(*a)不能进行赋值,而a的值却可以改变。

2)关于int *p[3]和int(*p)[3]的区别:

 前面一个是一个**指针数组**,它表示p是一个含有三个"数"的数组,每个"数"表示一个指向整型数的指针(用法:p[0]=&a);
 后面一个则是一个**指针**,它表示指针p是一个指向含有三个数的数组(用法:int a[3];int (*p)[3];p=a;)。

与此类似的还有:int *f();表示一个函数返回值为int *型(即函数指针);int (*p)f();表示一个指向函数的指针
具体内容在指针的进阶中再展开叙述。

二 关于sizeof和strlen:

**

sizeof

sizeof是运算符,在编译期间就计算好了,它的功能是:获取能保证现实建立最大对象的字节大小。由于是在编译期间计算的,所以sizeof不能返回动态开辟的空间的大小。如果sizeof遇上字符串数组,不要忘了后面还有\0的大小。

当有以下参数时,sizeof返回的值表示的含义为:

数组——编译时分配的数组空间的大小
指针——存储该指针的空间的大小(也就是存储指针的地址长度,32位机器不管对于任何类型的指针大小都为4,64位机器指针大小为8)
类型——该类型所占空间的大小

strlen

strlen是函数,在运行时才计算大小,它的参数是字符指针char*。当数组名作为参数传入时,实际上数组就退化为指针了。它的功能是:返回字符串的长度。实际上是这样工作的:从所给字符串的第一个地址开始遍历,遇到\0结束,返回长度不包括\0。

char arr[] = { 'a','b','c','d','e','f' };	
printf("%d\n", strlen(arr));//x
//因为没有\0结束,所以遍历整个数组不确定什么时候停止,结果为任意数	
printf("%d\n", strlen(arr + 0));//x
printf("%d\n", strlen(*arr));//err	
printf("%d\n", strlen(arr[1]));//err
//不满足strlen的工作条件,传入的参数要是地址,有时候是数组首元素(字符串的第一个地址)
printf("d\n", strlen(*p));//err
printf("d\n", strlen(p[0]));//err
正确的如下:
char arr[] = "abcdef";
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
char *p = "abcdef";
printf("d\n", strlen(p));//6	//a~f
printf("d\n", strlen(p + 1));//5   //b~f
//p是指针变量,*p里面存放的是a的地址		
	

笔试考试常见的题型:

为了方便理解,首先要了解:
1.C/C++里面的数组名会退化为指针,所以数组名a实际指的是数组的第一个元素的地址。而数组名作为指针来讲有特殊性,它正在它所指向的内存区域中,&a的值和a的数值是相同的,但是类型和意义不同。而指针的加法操作和指向的数据类型密切相关。

例如

int a[]; a就相当于int *,如果是对它加1,(a + 1)是相当于a + 1 * sizeof(int)int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a+0));//4
//a为首元素地址,(a+0)还是首元素地址
printf("%d\n", sizeof(a+1));//4
///第二个元素的地址

char *p = "abcdef";
printf("d\n", sizeof(p+1));//4
///第二个元素的地址


&a的类型则相当于int **,是所谓指向数组的指针,是数组元素类型的二级指针,对它加1是相当于 &a + 1 * sizeof(a)的,所以会偏移一个数组长度,即跳过这个数组的下一位地址。
char *p = "abcdef";
printf("d\n", sizeof(&p));//4
//指的是p的地址,即char**
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(&a+1));//4
//跳过这个数组,即4后面的地址
char arr[] = "abcdef";
printf("d\n", sizeof(arr + 0));//4
char arr[] = { 'a','b','c','d','e','f' };
printf("d\n", sizeof(&arr+1));//4
//跳过这个数组,但未知
char *p = "abcdef";
printf("d\n", sizeof(&p + 1));//4
//是一个地址,但不知道在哪里,与abcdef无关

strlen

char *p = "abcdef";
printf("d\n", strlen(&p));//x	
printf("d\n", strlen(&p + 1));//y
//&p的地址,与abcdef无关,不知道在哪里。
  1. sizeof(数组名),数组名表示的是整个数组,计算的是整个数组的大小。
//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16
//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("d\n", sizeof(arr));//6
    char arr[] = "abcdef";
	printf("d\n", sizeof(arr));//7(\0占长度)
//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48

strlen

char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(&arr));//x
printf("%d\n", strlen(&arr + 1));//x-6
printf("%d\n", strlen(&arr[0] + 1));//x-1
//因为没有\0结束,所以遍历整个数组不确定什么时候停止,结果为任意数,但&arr+1是跳过整个数组之后遍历,所以需要——6	

 char arr[] = "abcdef";//7元素,内含\0
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr + 1));//x	
//因为跳过整个数组,不确定什么时候遍历停止
printf("%d\n", strlen(&arr[0] + 1));//5
//从第二个元素开始遍历

2.&数组名,数组名表示的也是整个数组,此时&数组名指的是一个指针,而指针的大小也是4。

int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(&a));//4

char arr[] = { 'a','b','c','d','e','f' };
printf("d\n", sizeof(&arr));//4

char arr[] = "abcdef";
printf("d\n", sizeof(&arr));//4


3.除此之外所有的数组名都表示首元素地址。

int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a+0));//4
//a为首元素地址,(a+0)还是首元素地址
printf("%d\n", sizeof(a+1));//4
///第二个元素的地址
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a[0]));//16
//a[0]第一行数组名,即为第一行的总大小(4*4)	
printf("%d\n", sizeof(a[0]+1));//4
//第一行第二个元素	

4.数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组;数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量;指向数组的指针则是另外一种变量类型,仅仅意味着数组的存放地址!
例如:所以,对于数组a来说,a[0]和*a都是访问首元素,

	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(*a));//4
	printf("%d\n", sizeof(a[1]));//4
	printf("%d\n", sizeof(*&a));//16
//*解引用的对象是&a(整个数组的地址),即访问整个数组的大小

    char arr[] = { 'a','b','c','d','e','f' };
    printf("d\n", sizeof(arr[1]));//1
	printf("d\n", sizeof(*arr));//1
	printf("d\n", sizeof(arr[1]));//1
	char *p = "abcdef";
    printf("d\n", sizeof(p[0]));//1
    printf("d\n", sizeof(*p));//1
	//p是指针变量,*p里面存放的是a的地址,则*p表示访问a
   //二维数组
    int a[3][4] = { 0 };
	printf("%d\n", sizeof(a[0][0]));//4
   //首元素	

&a[0]+1和a+1都是第二个元素的地址

int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a+0));//4
//第一个元素地址
printf("%d\n", sizeof(&a[0]));//4
//第一个元素地址
printf("%d\n", sizeof(a+1));//4
printf("%d\n", sizeof(&a[0]+1));//4

char arr[] = { 'a','b','c','d','e','f' };
printf("d\n", sizeof(arr+0));//4
//第一个元素地址
printf("d\n", sizeof(&arr[0]+1));//4
//第二个元素地址
char *p = "abcdef";
printf("d\n", sizeof(&p[0] + 1));//4
printf("d\n", strlen(&p[0] + 1));//5
//符合strlen函数条件,参数是第二个元素的地址

//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(&a[0]+1));//4
//第二行的地址
printf("%d\n", sizeof(a+1));//4	
//第二行的地址	
printf("%d\n", sizeof(*(a+1)));//16
//访问第二行的所有元素	
printf("%d\n", sizeof(*(&a[0] + 1)));//16
//访问第二行的所有元素	

关于char* p

p 是一个指针变量,里面存放的是地址。例如char *p = “abcdef”;所以printf(“d\n”, sizeof(p)); 输出为4,32位机器不管对于任何类型的指针大小都为4。

二维数组

int a[3][4] = { 0 };
printf("%d\n", sizeof(*(a[0] + 1));//4
//访问第一行第二个元素	
printf("%d\n", sizeof(*a));//16
//首元素地址	
printf("%d\n", sizeof(a[3]));//16
//位置行列,但可以根据类型推断出来

在二维数组中,例如int a[10][20];a表示二维数组的数组名,也是首元素的地址,因此*(a+i)表示第i+1行0列元素的地址,即a[i][0],a+i表示的是第i+1行的首地址。

OK!这就是这段时间学到的 ,以后需要补充的继续补充。

发布了25 篇原创文章 · 获赞 5 · 访问量 342

猜你喜欢

转载自blog.csdn.net/weixin_44602007/article/details/104725416