本文主要讲解了c语言中指针的进阶内容,在初阶的基础上进行延伸.
内存会划分为一个个的内存单元
每个内存单元都有一个独立的编号,-编号也称为地址
地址在C语言中也被称为指针
指针(地址)需要存储起来-存储到变量中,这个变量也就被称为指针变量
指针(地址)的大小固定说4/8个字节(32位平台/64位平台)
地址是物理的电线上产生
32为机器-32根地址线 -1/0
32个0/1组成的二进制序列,把这个二进制序列作为地址,32bit位才能存储这个地址
也就是需要4个字节才能存储,所以指针变量的大小是4个字节
同理64位机器上,地址的大小是64个0/1组成的二进制序列,需要64bit位存储,也就是8个字节。所以指针变量的大小是8个字节。
在指针的类型中我们知道有一种指针类型为字符指针char*
- //在指针的类型中我们知道有一种指针类型为字符指针char*
- int main()
- {
- char ch = 'w';
- char* pc = &ch; //pc就是字符指针
- *pc = 'a';
-
- char arr[] = "abcdef"; //[a b c d e f \0]
- const char*p = "abcdef"; //常量字符串
- printf("%s\n",p); //abcdef
- printf("%c\n",*p); //a
-
- return 0;
- }
经典面试题小试牛刀
- int main()
- {
- char str1[] = "hello xiaofan.";
- char str2[] = "hello xiaofan.";
-
- const char* str3 = "hello xiaofan.";
- const char* str4 = "hello xiaofan.";
-
- if (str1 == str2)
- {
- printf("str1 and str2 are same\n"); //数组名是数组首元素地址
- }
- else
- {
- printf("str1 and str2 are not same\n");
- }
- if(str3 == str4)
- {
- printf("str3 and str4 are same\n");
- }
- else
- {
- printf("str3 and str4 are not same\n");
- }
-
- return 0;
- }
数组指针是数组还是指针 ----是指针哦
数组指针类比:
整型指针-指向整型变量的指针,存放整型变量的地址的指针变量
字符指针-指向字符变量的指针,存放字符变量的地址的指针变量
数组指针-指向数组的指针,存放的是数组的地址的指针变量
- //数组指针
- //数组名的理解
- //数组名是数组首元素的地址
- //2个例外:1.sizeof(数组名),这里的数组名不是数组首元素的地址,数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节
- //2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址
- //除此之外,所有的地方的数组名都是数组首元素的地址
- // int main()
- // {
- // int arr[10] = {0};
- // printf("%p\n",arr); // int*
- // printf("%p\n",arr+1);
-
- // printf("%p\n",&arr[0]); //int*
- // printf("%p\n",&arr[0]+1);
-
- // printf("%p\n",&arr); //int(*)[10]
- // printf("%p\n",&arr+1);
-
- // return 0;
- // }
-
- //对于数组名来说
- //&数组名得到的是数组的地址
- // int main()
- // {
- // int arr[10] = {1,2,3,4,5,6,7,8,9,10};
- // //数组的地址,存储到数组指针变量
- // //int[10] *p = &arr; //err
- // int(*p)[10] = &arr;
- // }
-
- // int main()
- // {
- // int arr[10] = {1,2,3,4,5,6,7,8,9,10};
- // int* p = arr;
- // int i = 0;
- // for (i = 0;i<10;i++)
- // {
- // printf("%d ",*(p+i));
- // }
- // }
-
- // int main()
- // {
- // int arr[10] = {1,2,3,4,5,6,7,8,9,10};
- // int (*p)[10] = &arr; //*&arr -> arr
- // int i = 0;
- // for (i = 0;i<10;i++)
- // {
-
- // printf("%d ",*((*p)+i));
- // printf("%d ",(*p)[i]);
- // }
- // }
-
- //数组指针怎么使用呢?一般在二维数组上才方便
-
- //二维数组传参,形参是二维数组的形式
- // void Printf(int arr[3][5],int r,int c)
- // {
- // int i = 0;
- // for (i = 0; i<3;i++)
- // {
- // int j = 0;
- // for(j = 0;j < 5;j++)
- // {
- // printf("%d ",arr[i][j]);
- // }
- // printf("\n");
- // }
- // }
- // int main()
- // {
- // int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
- // Printf(arr,3,5);
- // return 0;
- // }
-
- //二维数组传参,形参是指针的形式
- // void Printf(int (*p)[5],int r,int c)
- // {
- // int i = 0;
- // for(i = 0; i < r; i++)
- // {
- // int j = 0;
- // for (j = 0; j < c; j++)
- // {
- // printf("%d ",*(*(p+i)+j));
- // }
- // }
- // }
- // //二维数组的每一行可以理解为二维数组的一个元素
- // //每一行又是一个一维数组
- // //二维数组其实是一维数组的数组
- // //二维数组的数组名,也是数组名,数组名就是数组首元素地址
- // //arr - 首元素地址 - 第一行的地址 -一维数组的地址 -数组的地址
- // int main()
- // {
- // int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
- // //arr数组名是首元素地址
- // Printf(arr,3,5);
-
- // return 0;
-
- // }
-
-
- //一维数组传参,形参的部分可以是数组,也可以是指针
-
- // void test1(int arr[5],int sz)
- // {
-
- // }
-
- // void test2(int* p,int sz)
- // {
-
- // }
-
- // int main()
- // {
- // int arr[5] = {0};
- // test1(arr,5);
- // test2(arr,5);
-
- // return 0;
- // }
-
- //二维数组传参,形参的部分可以数组,也可以是指针
- void test3(char arr[3][5],int r,int c)
- {
- }
-
- void test4(char(*p)[5],int r,int c)
- {
- }
- int main()
- {
- char arr[3][5] = {0};
- test3(arr,4,5);
- test4(arr,3,5);
- return 0;
- }
指针数组
整型数组-存放整型的数组
字符数组-存放字符的数组
指针数组-存放指针的数组
- // int main()
- // {
- // int* arr[10];//存放整型指针的数组
- // char* arr2[10]; //一级字符指针的数组
- // char **arr3[10];//二级字符指针的数组
-
- // return 0;
- // }
-
- //使用指针数组模拟实现二维数组
- int main()
- {
- int arr1[] = {1,2,3,4,5};
- int arr2[] = {2,3,4,5,6};
- int arr3[] = {3,4,5,6,7};
-
- //指针数组
- int* arr4[3] = {arr1,arr2,arr3};
- printf("%d\n",arr4[1][1]);
-
- int i = 0;
- for ( i = 0; i < 3; i++)
- {
- /* code */
- int j = 0;
- for(j=0;j<5;j++)
- {
- printf("%d ",arr4[i][j]);
- //printf("%d ",*(arr4+i));
- }
- printf("\n");
- }
-
-
- return 0;
- }
在写代码的时候难免要把数组或者指针传给函数,那函数的参数该如何设计呢?
一维数组传参
二维数组传参
一级指针传参
二级指针传参

-
- //二维数组传参,形参是二维数组的形式
- // void Printf(int arr[3][5],int r,int c)
- // {
- // int i = 0;
- // for (i = 0; i<3;i++)
- // {
- // int j = 0;
- // for(j = 0;j < 5;j++)
- // {
- // printf("%d ",arr[i][j]);
- // }
- // printf("\n");
- // }
- // }
- // int main()
- // {
- // int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
- // Printf(arr,3,5);
- // return 0;
- // }
-
- //二维数组传参,形参是指针的形式
- // void Printf(int (*p)[5],int r,int c)
- // {
- // int i = 0;
- // for(i = 0; i < r; i++)
- // {
- // int j = 0;
- // for (j = 0; j < c; j++)
- // {
- // printf("%d ",*(*(p+i)+j));
- // }
- // }
- // }
- // //二维数组的每一行可以理解为二维数组的一个元素
- // //每一行又是一个一维数组
- // //二维数组其实是一维数组的数组
- // //二维数组的数组名,也是数组名,数组名就是数组首元素地址
- // //arr - 首元素地址 - 第一行的地址 -一维数组的地址 -数组的地址
- // int main()
- // {
- // int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
- // //arr数组名是首元素地址
- // Printf(arr,3,5);
-
- // return 0;
-
- // }
-
-
- //一维数组传参,形参的部分可以是数组,也可以是指针
-
- // void test1(int arr[5],int sz)
- // {
-
- // }
-
- // void test2(int* p,int sz)
- // {
-
- // }
-
- // int main()
- // {
- // int arr[5] = {0};
- // test1(arr,5);
- // test2(arr,5);
-
- // return 0;
- // }
-
- //二维数组传参,形参的部分可以数组,也可以是指针
- // void test3(char arr[3][5],int r,int c)
- // {
- // }
-
- // void test4(char(*p)[5],int r,int c)
- // {
-
- // }
- // int main()
- // {
- // char arr[3][5] = {0};
- // test3(arr,4,5);
- // test4(arr,3,5);
- // return 0;
- // }
-
- //一维数组传参
- // void test(int arr[]) //true
- // {}
- // void test(int arr[10]) //true
- // {}
- // void test(int* arr) //true
- // {}
- // void test2(int* arr[20]) //true
- // {}
- // void test2(int** arr)
- // {}
-
- // int main()
- // {
- // int arr[10] = {0}; //存放整型
- // int *arr2[20] = {0}; //存放地址
- // test(arr);
- // test2(arr2);
- // }
-
- //一级指针传参
- // void print(int* p,int sz)
- // {
- // int i = 0;
- // for(i = 0;i
- // {
- // printf("%d\n",*(p+i));
- // }
- // }
-
- // int main()
- // {
- // int arr[10] = {1,2,3,4,5,6,7,8,9};
- // int *p = arr;
- // int sz = sizeof(arr)/sizeof(arr[0]);
- // //一级指针p,传给函数
- // print(p,sz);
- // return 0;
- // }
-
- //二级指针传参
- void test(int** ptr)
- {
- printf("num = %d\n",**ptr);
- }
-
- int main()
- {
- int n = 10;
- int* p = &n;
- int** pp = &p;
- test(pp); //10
- test(&p); //10
-
- return 0;
- }
函数指针-指向函数的指针
数组指针-指向函数的指针
- //函数指针
- // int Add(int x,int y)
- // {
- // return x+y;
- // }
-
- // int main()
- // {
- // int arr[10] = {0};
- // int (*pa)[10] = &arr;
- // // //&arr;
- // // printf("%p\n",&Add);
- // // printf("%p\n",Add);
- // //函数名是函数的地址
- // //&函数名也是函数的地址
-
- // int (*pf)(int,int) =&Add; //pf是函数指针变量 int(*)(int int)是函数指针类型
- // }
-
- // void test(char* pc,int arr[10])
- // {}
-
- // int main()
- // {
- // void (*pf)(char*,int[10]) = &test;
-
- // return 0;
- // }
-
-
- int Add(int x,int y)
- {
- return x+y;
- }
-
- int main()
- {
- //int (*pf)(int,int) = &Add;
- int (*pf)(int,int) = Add;
- int r = Add(3,5);
- printf("%d\n",r);
-
- int m = (*pf)(4,5);
- printf("%d\n",m);
-
-
- return 0;
- }
-
- //void (*p)() -p是函数指针
- //void (*)()是函数指针类型
- // int main()
- // {
- // //调用0地址处的函数
- // //1.将0强制类型转换为void(*)() 类型的函数指针
- // //2.调用0地址处的这个函数
- // ( *( void (*)())0)();
- // }
-
- // typedef unsigned int uint;
- // typedef int* ptr_t;
-
- // //typedef int(*)[10] parr_t; //err
- // typedef int(*parr_t)[10] ; //true
- // typedef int (*pf_t)(int,int);
- // int main()
- // {
- // uint u1;
- // ptr_t p1;
- // int* p2;
- // //parr_t[10];
- // //pf_t(2,3);
-
- // return 0;
- // }
-
- int main()
- {
- //signal是一个函数声明
- //signal函数有2个参数,第一个参数是int,第二个参数类型是void(*)(int) 函数指针类型
- //该函数指针指向的函数有一个int类型的参数,返回类型是void
- //signal 函数的返回类型也是 void(*)(int) ,该函数指针指向的函数有一个int类型的参数,返回类型是void
- typedef void(*pf_t)(int);
- pf_t signal(int ,pf_t);
- void (* signal(int,void(*)(int)))(int);
-
- return 0;
- }
整型指针放在一个数组中
int* arr[5]; //整型指针数组
char* arr2[5];//字符指针数组
函数指针数组:数组的每个元素是函数指针类型
- //函数指针数组
- int Add(int x,int y)
- {
- return x + y;
- }
- int Sub(int x,int y)
- {
- return x - y;
- }
- int Mul(int x,int y)
- {
- return x * y;
- }
- int Div(int x,int y)
- {
- return x / y;
- }
- // int main()
- // {
- // int (*pf1)(int , int) = Add;
- // int (*pf2)(int , int) = Sub;
- // int (*pf3)(int , int) = Mul;
- // int (*pf4)(int , int) = Div;
- // //函数指针数组
- // int (*pfArr[4])(int , int) = {Add,Sub,Mul,Div};
-
- // return 0;
- // }
-
- void menu()
- {
- printf("**********************************\n");
- printf("******* 1.add 2.sub ************\n");
- printf("******* 3.mul 4.div ************\n");
- printf("******* 0.exit ************\n");
- printf("**********************************\n");
- }
-
- // int main()
- // {
- // int input = 0;
- // int x = 0;
- // int y = 0;
- // int ret = 0;
- // do
- // {
- // menu();
- // printf("请选择:>");
- // scanf("%d",&input);
- // switch (input)
- // {
- // case 1:
- // printf("请输入两个操作数:");
- // scanf("%d %d",&x,&y);
- // ret = Add(x,y);
- // printf("ret = %d\n",ret);
- // break;
- // case 2:
- // printf("请输入两个操作数:");
- // scanf("%d %d",&x,&y);
- // ret = Sub(x,y);
- // printf("ret = %d\n",ret);
- // break;
- // case 3:
- // printf("请输入两个操作数:");
- // scanf("%d %d",&x,&y);
- // ret = Mul(x,y);
- // printf("ret = %d\n",ret);
- // break;
- // case 4:
- // printf("请输入两个操作数:");
- // scanf("%d %d",&x,&y);
- // ret = Div(x,y);
- // printf("ret = %d\n",ret);
- // break;
- // case 0:
- // printf("退出计算器\n");
- // break;
- // default:
- // printf("选择错误重新选择");
- // break;
- // }
- // } while(input);
-
- // return 0;
- // }
-
- //函数指针的方式
- int main()
- {
- int input = 0;
- int x = 0;
- int y = 0;
- int ret = 0;
- //函数指针数组的使用 - 转移表
- int (*pfArr[5])(int,int) = {NULL,Add,Sub,Mul,Div};
- do
- {
- menu();
- printf("请选择:>");
- scanf("%d",&input);
- if(input >=1 && input <=4)
- {
- printf("请输入两个操作数:");
- scanf("%d %d",&x,&y);
- ret = pfArr[input](x,y);
- printf("ret = %d\n",ret);
- }
- else if(input == 0)
- {
- printf("退出计算器\n");
- }
- else
- {
- printf("选择错误,重新选择\n");
- }
-
- } while(input);
-
- return 0;
- }
int(*pf)(int,int);//函数指针
int(*pfArr[4])(int,int);//函数指针数组
int(*(*p)[4](int,int) = &pfArr);//函数指针数组的地址
p就是指向函数指针数组的指针
- void test(const char* str)
- {
- printf("%\n",str);
- }
-
- int main()
- {
- //函数指针pfun
- void (*pfun)(const char*) = test;
- //函数指针的数组pfunArr
- void (*pfunArr[5])(const char* str);
- pfunArr[0] = test;
- //指向函数指针数组pfunArr的指针ppfunArr
- void (*(*ppfunArr)[5])(const char*) = &pfunArr;
- return 0;
- }
回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数,回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
- //回调函数
- // int Add(int x,int y)
- // {
- // return x + y;
- // }
- // int Sub(int x,int y)
- // {
- // return x - y;
- // }
- // int Mul(int x,int y)
- // {
- // return x * y;
- // }
- // int Div(int x,int y)
- // {
- // return x / y;
- // }
-
- // void menu()
- // {
- // printf("**********************************\n");
- // printf("******* 1.add 2.sub ************\n");
- // printf("******* 3.mul 4.div ************\n");
- // printf("******* 0.exit ************\n");
- // printf("**********************************\n");
- // }
-
- // void Calc(int (*pf)(int x,int y))
- // {
- // int x = 0;
- // int y = 0;
- // int ret = 0;
- // printf("请输入两个操作数:\n");
- // scanf("%d %d",&x,&y);
- // ret = pf(x,y);
- // printf("ret = %d\n",ret);
-
- // }
-
- // int main()
- // {
- // int input = 0;
- // int x = 0;
- // int y = 0;
- // int ret = 0;
- // do
- // {
- // menu();
- // printf("请选择:>");
- // scanf("%d",&input);
- // switch (input)
- // {
- // case 1:
- // Calc(Add);
- // break;
- // case 2:
- // Calc(Sub);
- // break;
- // case 3:
- // Calc(Mul);
- // break;
- // case 4:
- // Calc(Div);
- // break;
- // case 0:
- // printf("退出计算器\n");
- // break;
- // default:
- // printf("选择错误重新选择");
- // break;
- // }
- // } while(input);
-
- // return 0;
- // }
-
- //冒泡排序
- //有一组整数,需要排序为升序
- //1.两两相邻的元素比较
- //2.如果不满足顺序就交换
-
- // int main()
- // {
- // int arr[10] = {9,8,7,6,5,4,3,2,1,0};
- // int sz = sizeof(arr)/sizeof(arr[0]);
- // int i = 0;
- // //int a = qsort(arr[10]);
- // //bubble_sort(arr,sz);
- // //趟数
- // for(i = 0;i < sz-1; i++)
- // {
- // //一趟比较
- // //两两元素比较
- // int j = 0;
- // for (j = 0;j
- // {
- // if(arr[j] > arr[j+1])
- // {
- // int tmp = arr[j];
- // arr[j] = arr[j+1];
- // arr[j+1] = tmp;
- // }
- // }
- // }
-
- // for (i = 0; i
- // {
- // printf("%d ",arr[i]);
- // }
-
-
-
- // return 0;
- // }
-
- //qsort 函数的特点
- //1.快速排序的方法quick
- //2.适用于任何类型数据的排序
-
- // void qsort(void *__base, //指向了需要排序的数组的第一个元素
- // size_t __nel, //排序的元素个数
- // size_t __width,//一个元素的大小,单位是字节
- // int (* _Nonnull __compar)(const void *, const void *));//函数指针类型-这个函数指针指向的函数,能够比较base指向数组中的两个元素
-
- int cmp_int(const void*p1,const void*p2)
- {
- return (*(int*)p1 - *(int*)p2);
- }
- void print(int arr[],int sz)
- {
- int i = 0;
- for(i = 0;i
- {
- printf("%d ",arr[i]);
- }
- }
-
- //测试qsort排序整型数据
- void test1()
- {
- int arr[10] = {9,8,7,6,5,4,3,2,1};
- int sz = sizeof(arr)/sizeof(arr[0]);
- //默认是升序的
- qsort(arr,sz,sizeof(int),cmp_int);
- print(arr,sz);
- }
-
-
- //测试qsort排序结构体数据
- struct Stu
- {
- char name[20];
- int age;
- };
-
- int cmp_stu_by_age(const void* p1,const void* p2)
- {
- return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
- }
-
- int cmp_stu_by_name(const void* p1,const void* p2)
- {
- return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);
- }
-
- void test2()
- {
- struct Stu arr[] = { {"张三",18}, {"李四,20"},{"王五,16"}};
- int sz = sizeof(arr)/sizeof(arr[0]);
- qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_age);
- }
-
- void test3()
- {
- struct Stu arr[] = { {"张三",18}, {"李四,20"},{"王五,16"}};
- int sz = sizeof(arr)/sizeof(arr[0]);
- qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);
- }
-
-
- int main()
- {
- //test1();
- //test2();
- test3();
-
- return 0;
- }
-
- //void* 指针
- //void*类型的指针可以接受任意类型的地址
- //这种类型的指针是不能直接解引用操作的
- //也不能直接进行指针运算的
-
- // int main()
- // {
- // int a = 10;
- // float f = 3.14f;
- // int* pa = &a;
- // char* pc = &a;
- // void* pv = &a;
-
- // }
//使用冒泡排序的思想,实现一个功能类似qsort函数 bubble_sort()
//1.使用冒泡排序的思想
//2.适用于任意类型数据的排序
- //使用冒泡排序的思想,实现一个功能类似qsort函数 bubble_sort()
- //1.使用冒泡排序的思想
- //2.适用于任意类型数据的排序
-
- void Swap(char* buf1,char* buf2,int size)//交换arr[j],arr[j+1]这两个元素
- {
- int i = 0;
- int tmp = 0;
- for(i = 0;i < size;i++)
- {
- tmp = *buf1;
- *buf1 = *buf2;
- *buf2 = tmp;
- //char*指针一次只能交换一个字节,但是char有四个字节
- buf1++;
- buf2++;
- }
- }
-
- void bubble_sort(void* base,int num,int size,int (*cmp)(const void*,const void*))
- {
- int i = 0;
- //趟数
- for (i = 0; i < num - i; i++)
- {
- int j = 0;
- //一趟内部比较的对数
- for(j = 0; j < num - 1; j++)
- {
- //假设需要升序,cmp返回>0,交换
- if(cmp((char*)base+j*size,(char*)base+(j+1)*size) > 0) //两个元素比较,需要将arr[j],arr[j+1]的地址要传给cmp
- {
- //交换
- Swap((char*)base + j * size,(char*)base + (j+1) * size,size);
- }
- }
- }
- }
-
- int cmp_int(const void*p1,const void*p2)
- {
- return (*(int*)p1 - *(int*)p2);
- }
-
-
- //测试bubble_sort()排序整型数据
- void test1()
- {
- int arr[10] = {9,8,7,6,5,4,3,2,1};
- int sz = sizeof(arr)/sizeof(arr[0]);
- bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
- }
-
- //测试bubble_sort()排序结构体数据
-
- struct Stu
- {
- char name[20];
- int age;
- };
-
-
- int cmp_stu_by_age(const void* p1,const void* p2)
- {
- return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
- }
-
- int cmp_stu_by_name(const void* p1,const void* p2)
- {
- return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);
- }
-
- void test2()
- {
- struct Stu arr[] = { {"张三",18}, {"李四,20"},{"王五,16"}};
- int sz = sizeof(arr)/sizeof(arr[0]);
- bubble_sort(arr,sz,sizeof(arr[0]),cmp_stu_by_age);
- }
-
- void test3()
- {
- struct Stu arr[] = { {"zhangsan",18}, {"lisi,20"},{"wangwu,16"}};
- int sz = sizeof(arr)/sizeof(arr[0]);
- bubble_sort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);
- }
-
- int main()
- {
- //test1();
- //test2();
- test3();
- return 0;
- }
九、指针和数组面试题的解析
// 数组名的理解
// 数组名是数组首元素的地址
// 但是有2个例外:
// 1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
// 2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
// int main()
// {
// //一维数组
// int a[] = {1, 2, 3, 4};
// printf("%d\n", sizeof(a)); // 4*4=16
// printf("%d\n", sizeof(a + 0)); //数组名a是数组首元素的地址,a+0还是首元素地址,地址的大小4/8
// printf("%d\n", sizeof(*a));//数组名a是数组首元素的地址,*a就是首元素,int类型大小4个字节
// printf("%d\n", sizeof(a + 1));//数组名a是数组首元素的地址,a+1是第二个元素的地址,地址的大小是4/8
// printf("%d\n", sizeof(a[1]));//4
// printf("%d\n", sizeof(&a));//&a是数组的地址,数组的地址也是地址,是4/8个字节
// printf("%d\n", sizeof(*&a));// --> sizeof(a) ,*&a,取地址解引用a就是a 16
// printf("%d\n", sizeof(&a + 1)); //8
// printf("%d\n", sizeof(&a[0]));// 首元素地址 4/8字节
// printf("%d\n", sizeof(&a[0] + 1));//&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,地址就是4/8个字节
// }
int main()
{
// 字符数组
char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
// printf("%d\n", sizeof(arr)); //计算的是整个数组的大小,单位是字节,总共6个字节
// printf("%d\n", sizeof(arr + 0)); //arr表示数组首元素地址,arr+0还是数组首元素地址,地址就是4/8字节
// printf("%d\n", sizeof(*arr));//arr是首元素地址,*arr是首元素,大小1个字节
// printf("%d\n", sizeof(arr[1]));//1
// printf("%d\n", sizeof(&arr));//&arr是数组的地址 地址就是4/8
// printf("%d\n", sizeof(&arr + 1)); //地址就是4/8
// printf("%d\n", sizeof(&arr[0] + 1)); //地址是4/8
printf("%d\n", strlen(arr)); //因为字符数组arr中没有\0,所以求字符串长度的时候,会一直往后找,产生的结构就是随机值
printf("%d\n", strlen(arr + 0));// arr+0 是首元素的地址,和第一个一样,也是随机值
//printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*arr就是数组首元素 就是'a'-97
//strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,‘a’的ASCII码值就是97,那就是将97作为地址传参
//strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
//printf("%d\n", strlen(arr[1])); //err
printf("%d\n", strlen(&arr));//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,传递给strlen函数后,依然是从数组的第一个元素的位置,还是往后统计
printf("%d\n", strlen(&arr + 1));//跳过这个数组 ,随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,随机值-1
}
- #include
- #include
-
- // 数组名的理解
- // 数组名是数组首元素的地址
- // 但是有2个例外:
- // 1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
- // 2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
-
- // int main()
- // {
- // //一维数组
- // int a[] = {1, 2, 3, 4};
- // printf("%d\n", sizeof(a)); // 4*4=16
- // printf("%d\n", sizeof(a + 0)); //数组名a是数组首元素的地址,a+0还是首元素地址,地址的大小4/8
- // printf("%d\n", sizeof(*a));//数组名a是数组首元素的地址,*a就是首元素,int类型大小4个字节
- // printf("%d\n", sizeof(a + 1));//数组名a是数组首元素的地址,a+1是第二个元素的地址,地址的大小是4/8
- // printf("%d\n", sizeof(a[1]));//4
- // printf("%d\n", sizeof(&a));//&a是数组的地址,数组的地址也是地址,是4/8个字节
- // printf("%d\n", sizeof(*&a));// --> sizeof(a) ,*&a,取地址解引用a就是a 16
- // printf("%d\n", sizeof(&a + 1)); //8
- // printf("%d\n", sizeof(&a[0]));// 首元素地址 4/8字节
- // printf("%d\n", sizeof(&a[0] + 1));//&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,地址就是4/8个字节
- // }
-
- // int main()
- // {
- // // 字符数组
- // char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
- // // printf("%d\n", sizeof(arr)); //计算的是整个数组的大小,单位是字节,总共6个字节
- // // printf("%d\n", sizeof(arr + 0)); //arr表示数组首元素地址,arr+0还是数组首元素地址,地址就是4/8字节
- // // printf("%d\n", sizeof(*arr));//arr是首元素地址,*arr是首元素,大小1个字节
- // // printf("%d\n", sizeof(arr[1]));//1
- // // printf("%d\n", sizeof(&arr));//&arr是数组的地址 地址就是4/8
- // // printf("%d\n", sizeof(&arr + 1)); //地址就是4/8
- // // printf("%d\n", sizeof(&arr[0] + 1)); //地址是4/8
- // printf("%d\n", strlen(arr)); //因为字符数组arr中没有\0,所以求字符串长度的时候,会一直往后找,产生的结构就是随机值
- // printf("%d\n", strlen(arr + 0));// arr+0 是首元素的地址,和第一个一样,也是随机值
- // //printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*arr就是数组首元素 就是'a'-97
- // //strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,‘a’的ASCII码值就是97,那就是将97作为地址传参
- // //strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了
- // //printf("%d\n", strlen(arr[1])); //err
- // printf("%d\n", strlen(&arr));//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,传递给strlen函数后,依然是从数组的第一个元素的位置,还是往后统计
- // printf("%d\n", strlen(&arr + 1));//跳过这个数组 ,随机值
- // printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,随机值-1
- // return 0;
- // }
-
- // int main()
- // {
- // char arr[] = "abcdef"; //[a b c d e f \0]
- // // printf("%d\n", sizeof(arr)); //7
- // // printf("%d\n", sizeof(arr + 0)); //arr+0是首元素地址 4/8
- // // printf("%d\n", sizeof(*arr)); // *arr首元素 char类型是1
- // // printf("%d\n", sizeof(arr[1]));//下标1的元素b 1
- // // printf("%d\n", sizeof(&arr)); //地址就是4/8
- // // printf("%d\n", sizeof(&arr + 1));//地址 4/8
- // // printf("%d\n", sizeof(&arr[0] + 1));//地址4/8
-
- // printf("%d\n", strlen(arr));//6
- // printf("%d\n", strlen(arr + 0)); //6
- // //printf("%d\n", strlen(*arr)); //err
- // //printf("%d\n", strlen(arr[1])); //err
- // printf("%d\n", strlen(&arr)); //6
- // printf("%d\n", strlen(&arr + 1));//随机值
- // printf("%d\n", strlen(&arr[0] + 1));//5
- // return 0;
- // }
-
- // int main()
- // {
- // char *p = "abcdef"; //[a b c d e f \0]
- // // printf("%d\n", sizeof(p)); //p是一个指针变量,大小就要4/8个字节
- // // printf("%d\n", sizeof(p + 1)); //p+1是b的地址,是地址大小就是4/8个字节
- // // printf("%d\n", sizeof(*p)); //*p首元素,字符a 1个字节
- // // printf("%d\n", sizeof(p[0]));//p[0] = *(p+0) = *p 1
- // // printf("%d\n", sizeof(&p)); // 4/8 p = char* &p = char**
- // // printf("%d\n", sizeof(&p + 1));// 4/8
- // // printf("%d\n", sizeof(&p[0] + 1));// 4/8
-
- // printf("%d\n", strlen(p)); //6
- // printf("%d\n", strlen(p + 1));//5
- // //printf("%d\n", strlen(*p));// err *p = a
- // //printf("%d\n", strlen(p[0]));// p[0] = *(p+0) = *p err
- // printf("%d\n", strlen(&p));//随机值
- // printf("%d\n", strlen(&p + 1));//随机值
- // printf("%d\n", strlen(&p[0] + 1));//&p[0]+1 是b 5
- //return 0;
- // }
-
- int main()
- {
- // 二维数组
- int a[3][4] = {0};
- printf("%d\n", sizeof(a)); //3*4*4
- printf("%d\n", sizeof(a[0][0]));//4
- printf("%d\n", sizeof(a[0])); //4*4
- printf("%d\n", sizeof(a[0] + 1)); // 4/8
- //a[0]作为第一行的数组名,没有单独放在sizeof内部,没有&
- //a[0]表示数组首元素的地址,也就是a[0][0]的地址
- //a[0]+1是第一行第二个元素的地址
- //地址就是4/8
- printf("%d\n", sizeof(*(a[0] + 1)));//计算的就是第一行第2个元素的大小 4个字节
- printf("%d\n", sizeof(a + 1)); // 4/8
- //a是数组首元素的地址,是第一行的地址
- //a+1就是第二行的地址
- printf("%d\n", sizeof(*(a + 1))); //4*4
- //*(a+1)--> a[1] -> sizeof(a[1]),计算第二行的大小
- //a+1就是第二行的地址,*(a+1)计算第二行的大小
- printf("%d\n", sizeof(&a[0] + 1));// 4/8
- //&a[0]第一行的地址
- //&[0]+1第二行的地址
- printf("%d\n", sizeof(*(&a[0] + 1))); //第二行的大小 4*4
- printf("%d\n", sizeof(*a)); //4*4
- //a是数组首元素地址,就是第一行地址
- //*a就是第一行
- //*a --> *(a+0) --> a[0]
- printf("%d\n", sizeof(a[3])); //4*4
- //a[3] --> int[4]
-
- return 0;
- }
//总结:数组名的意义
//1sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
//2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
//3.除此之外所有的数组名都表示首元素的地址
- // 笔试题1
- // int main()
- // {
- // int a[5] = { 1, 2, 3, 4, 5 };
- // int *ptr = (int *)(&a + 1);
- // printf( "%d,%d", *(a + 1), *(ptr - 1)); //2 5
- // return 0;
- // }
-
- // 笔试题2
- // 由于还没学习结构体,这里告知结构体的大小是20个字节
- // struct Test
- // {
- // int Num;
- // char *pcName;
- // short sDate;
- // char cha[2];
- // short sBa[4];
- // } *p = (struct Test*)0x100000;
- // // 假设p 的值为0x100000。 如下表表达式的值分别为多少?
- // int main()
- // {
- // printf("%p\n", p + 0x1); //0x100020 +1跳过一个结构体就是20个字节
- // printf("%p\n", (unsigned long)p + 0x1);//0x100001
- // printf("%p\n", (unsigned int *)p + 0x1); //0x100004
- // return 0;
- // }
-
-
- //笔试题3
- // int main()
- // {
- // int a[4] = {1, 2, 3, 4};
- // int *ptr1 = (int *)(&a + 1);
- // int *ptr2 = (int *)((int)a + 1);
- // printf("%x\n,%x\n", ptr1[-1], *ptr2);
- // return 0;
- // }
-
- //笔试题4
- // #include
- // int main()
- // {
- // int a[3][2] = { (0, 1), (2, 3), (4, 5) };
- // int *p;
- // p = a[0]; //a[0] --> &a[0][0]
- // printf( "%d", p[0]);//p[0] --> *(p+0) -->*p 1
- // return 0;
- // }
-
- //笔试题5
- // int main()
- // {
- // int a[5][5];
- // int(*p)[4];
- // //p --> int(*)4 a -->int(*)5
- // p = a;
- // printf( "%p,%d\n",
- // &p[4][2] - &a[4][2],
- // &p[4][2] - &a[4][2]);
- // return 0;
- // }
-
- //笔试题6
- // int main()
- // {
- // int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- // int *ptr1 = (int *)(&aa + 1);
- // int *ptr2 = (int *)(*(aa + 1));
- // printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10 5
- // return 0;
- // }
-
- //笔试题7
- // int main()
- // {
- // char *a[] = {"work","at","alibaba"};//char* work char* at char* alibaba
- // char**pa = a;
- // pa++; //0 work 1 at 2 alibaba
- // printf("%s\n", *pa); //at
- // return 0;
- // }
-
- //笔试题8
- int main()
- {
- char *c[] = {"ENTER","NEW","POINT","FIRST"};
- char**cp[] = {c+3,c+2,c+1,c};
- char***cpp = cp;
- printf("%s\n", **++cpp);
- printf("%s\n", *--*++cpp+3);
- printf("%s\n", *cpp[-2]+3);
- printf("%s\n", cpp[-1][-1]+1);
- return 0;
- }
笔试题3

笔试题5
笔试题6

总结:本章主要对指针在初阶的基础上更深一步的进行了研究,对指针地址和解引用都有详细的讲解,如需初阶可以观看C语言基础-指针_小凡喜编程的博客-CSDN博客