索引
1,关于常量字符串的探讨
先看一串代码
char arr1[] = "hello world!";
char arr2[] = "hello world!";
char* arr3 = "hello world!";
char* arr4 = "hello world!";
if (arr1 == arr2)
printf("arr1 and arr2 are same\n");
else
printf("arr1 and arr2 are not same\n");
if(arr3==arr4)
printf("arr3 and arr4 are same\n");
else
printf("arr1 and arr2 are not same\n");
代码的输出结果是这样的
arr1 and arr2 are not same
arr3 and arr4 are same
常量字符串类似于“abcdef它是位于只读数据区,只能写不能改的,常量字符串只能存储一次,而上述的char*arr3 = "hello world!“其实只村粗了这个常量字符串的首元素的地址,而arr4也是一样,所以他们俩才会相等,因为直接是被常量字符串赋值的,但是arr1与arr2不一样,他们相当于各自开辟了新的空间,然后那一块空间上的字符串是"hello world”,虽然此时arr1与arr2都表示字符串首元素的地址,但是代表的是他们各自开辟空间的首元素的地址,这是不一样的,所以才会出现arr1 and arr2 are not same;
总结假设有一个常量字符串“abcdef”虽然我们看到的是"abcdef"但是在内存中存储的其实是a的地址也就是首元素的地址.
2,数组指针与指针数组如何辨别
int* arr1[10]; //arr1先于中括号结合表示此时arr1是一个数组,然后此时arr1的元素是int*整形指针所以此时的arr1是一个指针数组,本质还是数组,也就是整形指针数组
char *arr2[4];//arr2和arr1一样,先与中括号结合表示这是一个数组,然后数组的元素是char*所以此时的arr2表示的是一个字符数组
char **arr3[5];//同理,只不过arr3的元素是char**表示的是字符二级指针,所以此时arr3表示的是二级指针数组
char (*arr4)[10]//表示的数组指针,此时arr4先于*结合表示此时arr4是一个指针,指向的是有10元素的数组,该数组每个元素是char
int (*arr5[10])[5]//arr5先于中括号结合表示这是一个数组,那么此时arr5数组的元素类型是什么?将arr5[10]盖住,剩下的就是改元素类型,该类型是int(*)[5]该类型是指向有五个ing数组的指针所以arr5的本质还是指针数组
3,关于二维数组的探究
二维数组首元素地址
如果有一个二维数组int arr[]2[5] = {1,2,3,4,5,6,7,8,9,10}
数组的arr也表示的是首元素的地址,但是如果是二维数组的话,那么其首元素的地址其实该二维数组的第一行也就是arr[0]五个元素的地址,并不是arr[0][0],虽然二者在地址大小的表示上也许都是一样的,但是本质上还是不同的
二维数组传参
void test(int arr[2][5])//可以
{}
void test(int arr[][])//不行
{}
void test(int arr[][5])//可以
{}
//总结:二维数组传参必须函数的形参最多省略第一个[]数字,第二个数字是不能省略的
// 个人理解:
// 虽然我们理解二维数组的时候,是用一个二维图理解的,将数组分成几行几列,
// 但是实际数组在内存中的存储是连续存储的,如果连第二个表示列的数组都省略了
// 那么编译器在编译的时候连什么时候该换行都不知道,但是行号不知道却可以,因为
// 行走完了,就没有了,那么便不需要行号也就是第一个数字了(以上仅仅是个人的理解觉得理解有大问题欢迎补充)
//
//
// 当然二维数组除了可以传类似上面的,还可以传指针
//但是要知道二维数组传参传进去的是数组首元素的地址,而数组首元素的地址在二维数组中其实是第一行的地址
void test(int(*p)[5])//传进去的指针表示的是指向五个元素并且元素类型是int的指针,恰好和二维数组第一行所对应
{}
//
4, 函数指针的相关介绍
指向函数的指针
1,函数指针如何表示
int test(int x, int y) {}//int (*p)(int,int) //*p表示p是一个指针,后面的圆括号表示此时p是一个函数指针,
// 函数的形参类型是(int,int)返回类型也是int
void test2(int x){}//void(*ps)(int) //*ps表示ps是一个指针,后面的圆括号表示此时的ps是一个函数指针
//此时函数的形参类型是(int)返回类型是void
函数指针数组 在我看来其实和指针数组差不多,就是加[]的事情,例如上面的
如果int(*p[5])(int,int)那么此时p先与[]结合表示此时p是一个数组,将p[]盖住
表示的就是此时数组的元素类型,int(*)(int,int),和指针数组相似度极高
函数指针的简单应用
int test(int x, int y)
{
return x + y;
}
int main()
{
int(*p)(int, int) = &test;
int c = p(2, 3);
int d = (*p)(4, 6);
printf("%d\n%d\n", c, d);
int(*ps)(int, int) = test;
int c1 = ps(2, 3);
int d1 = (*ps)(4, 6);
printf("%d\n%d", c1, d1);
return 0;
}
剖析发现上述的运行结果都是一样的
所以其实函数名和数组相似,单独一个函数名表示的就是函数的地址,而函数指针的*
在用指针调用函数的时候加不加其实没什么关系,但是我还是觉的加一下好,这样才能看出来他是一个指针hh
指针数组相关笔试题:
1,试题之前的补充
指针试题:
注意只要是指针,那么与编译器的环境有关,如果是在64平台下,那么指针的大小就是8如果是在32位平台下,那么其大小就是4,为了形象,我用的都是在64平台下操作的
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16数组和整个sizeof连用表示的是整个数组,表示的并不是首元素地址
printf("%d\n", sizeof(a + 0));//表示的是指针 未出现与sizeof与&那么此时a表示的首元素地址,地址+-也还是地址
printf("%d\n", sizeof(*a));//4 a表示的是首元素地址,首元素地址解引用表示的就是首元素大小也就是int
printf("%d\n", sizeof(a + 1));//表示的是指针 地址+-也还是地址
printf("%d\n", sizeof(a[1]));//4 表示的是首元素
printf("%d\n", sizeof(&a));//表示的是指针 只要加一个取地址并且前面没有解引用,那么就是指针
printf("%d\n", sizeof(*&a));//16
//巧记:我们可以理解*和&的作用抵消了,那么表示的就是sizeof(a)
//本质理解:&a此时表示的是int(*p)[4],加一个解引用的话此时表示的就是一个含有四个整形元素的数组,所以sizeof的值就是16
printf("%d\n", sizeof(&a + 1));//表示的是指针 指针的加减依然还是指针
printf("%d\n", sizeof(&a[0]));//指针
printf("%d\n", sizeof(&a[0] + 1));//指针
//strlen计算的是'\0'前面元素的个数,而sizeof计算的就是你数组中元素个数的大小
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//6
printf("%d\n", sizeof(arr + 0));//指针
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//指针
printf("%d\n", sizeof(&arr + 1));//指针
printf("%d\n", sizeof(&arr[0] + 1));//指针
printf("%d\n", strlen(arr));//随机值
printf("%d\n", strlen(arr + 0));//随机值
printf("%d\n", strlen(*arr));//随机值(其实是不合法的)会报错 因为strlen要求传入的值地址,但此时传入的是该数组首元素,
//表示的并不是地址,所以会报错
printf("%d\n", strlen(arr[1]));//同上 报错
printf("%d\n", strlen(&arr));//随机值 最后三个都不会报错,但是由于该字符没有'\0'并不知道在哪停止,所以会出现随机值
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
char arr[] = "abcdef";//实际上这个字符串表示的是abcdef\0里面有七个元素
printf("%d\n", sizeof(arr));//arr与sizeof连接,表示的是整个字符串
printf("%d\n", sizeof(arr + 0));//指针
printf("%d\n", sizeof(*arr));//1 表示该字符串的第一个元素
printf("%d\n", sizeof(arr[1]));//同上
printf("%d\n", sizeof(&arr));//表示的是指针
printf("%d\n", sizeof(&arr + 1));//指针
printf("%d\n", sizeof(&arr[0] + 1));//指针
printf("%d\n", strlen(arr));//6因为此时的字符串是有'\0'的 所以strlen计算的就是\0前面的字符
printf("%d\n", strlen(arr + 0));//6arr表示的是字符串首元素的地址,地址不论加减啥依旧还是地址,加0等于没加,所以还是6
//printf("%d\n", strlen(*arr));//此时的*arr表示的是字符串首元素,会报错
//printf("%d\n", strlen(arr[1]));//同上
printf("%d\n", strlen(&arr));//6 该地址和字符串首元素地址的值是一样的,只不过表示的含义不一样
//arr表示的是char元素的首地址
//&arr表示的是char(*p)[7]是一个指向数组的指针
printf("%d\n", strlen(&arr + 1));//此时跳过整个数组,所以是一个随机值
printf("%d\n", strlen(&arr[0] + 1));//是数组的首元素加1 此时从该地址到\0有五个元素,所以是5
char* p = "abcdef";//此时p存储的就是该字符串首元素的地址
printf("%d\n", sizeof(p));//指针
printf("%d\n", sizeof(p + 1));//还是指针
printf("%d\n", sizeof(*p));//1 首元素解引用代表的是a
printf("%d\n", sizeof(p[0]));//1
printf("%d\n", sizeof(&p));//指针的取地址还是一个指针,表示地址
printf("%d\n", sizeof(&p + 1));//指针不管加减都是指针带下跟编译器所处平台大小有关
printf("%d\n", sizeof(&p[0] + 1));//还是一个指针
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5
//printf("%d\n", strlen(*p));//会报错,此时传进去的并不是一个地址而是一个元素
//printf("%d\n", strlen(p[0]));//同上
printf("%d\n", strlen(&p));//随机值,此时传进去的是p指针的地址,和字符串的地址无关
printf("%d\n", strlen(&p + 1));//同上
printf("%d\n", strlen(&p[0] + 1));//5 首元素地址加1变成第二个元素的地址
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//表示的是整个整形数组 12*4 = 48
printf("%d\n", sizeof(a[0][0]));//第一个元素 4
printf("%d\n", sizeof(a[0]));//此时的a[0]与sizeof放在一起表示第一行元素 4 * 4 = 16
printf("%d\n", sizeof(a[0] + 1));//此时的a[0]表示的是第一行首元素的地址,是一个指针
//该指针类型是int*加1后还是指针
printf("%d\n", sizeof(*(a[0] + 1)));//(a[0]+1)表示的是第一行元素中的第二个元素,此时解引用
//后表示的就是一个整形的大小
printf("%d\n", sizeof(a + 1));//表示的是数组首元素的地址加1还是指针,
//但整个地址是代表第二行元素的地址
//指针的类型是int(*p)[4]
printf("%d\n", sizeof(*(a + 1)));//根据上述解释此时解引用表示的就是第二行元素的大小 4*4 = 16
printf("%d\n", sizeof(&a[0] + 1));//地址
printf("%d\n", sizeof(*(&a[0] + 1)));//(&a[0]+1)表示的就是第二行元素的地址,此时解引用表示的就是4*4 = 16
printf("%d\n", sizeof(*a));//a表示的是首元素的地址,但是因为二维数组首元素代表的是第一行元素,所以此时解引用后也是16
printf("%d\n", sizeof(a[3]));//按道理来说这个应该是越界了的 但是没关系
//假设又int a = 1;
// 计算sizeof(a)->sizeof(int)此时sizeof推导a是整形类型
// 而此时的sizeof(a[3])sizeof也会推导,其实就跟sizeof(a[0]),sizeof(a[1])一样此时的类型是int[4]
// sizeof不会真的去访问是否有a[3]这个元素的存在,只会推导,所以也还是不会报错的
printf("%d\n", sizeof(a[4]));//同上