1. 字符指针
int main()
{
char ch = 'W';
char *pc = &ch;//pc指向一个字符变量
const char* p = "hello bit!";//"hello bit!"为一个常量字符串 - 存放在内存的常量区
printf("%c\n", *p);//h
printf("%s\n", p);//hello bit!
//上面表达式表示:吧常量字符串"hello bit!"第一个字符h的地址赋值给p
return 0;
}
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char* str3 = "hello bit.";
char* str4 = "hello bit.";
if (str1 == str2)//比较两个数组的地址
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)//str3,str4都指向同一个h
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
上面的str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
2. 指针数组
指针数组就是:用来存放指针的数组
int main()
{
//char* arr[5];//arr为字符指针数组
//int* arr2[4];//arr2为整型指针数组
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int* arr2[4] = { &a,&b,&c,&d };//arr2为整型指针数组
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", *(arr2[i]));
}
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* parr[] = { arr1,arr2,arr3 };//这里的arr1,arr2,arr3代表数组首元素的地址。
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);//parr[i][j] == *(parr[i]+j)
}
printf("\n");
}
return 0;
}
int main()
{
const char* arr[5] = { "abcdef","bcdefg","hehe","haha","zhangsan" };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
3. 数组指针
3.1 数组指针定义
//定义
int mian()
{
int a = 10;
int* pi = &a;//整型的地址存放在整型指针中
char ch = 'w';
char* pc = &ch;//字符的地址存放在字符指针中
int arr[10] = { 0 };
int* p = arr;//arr -数组名是数组首元素的地址
int (*parr)[10] = &arr;//取出的是数组的地址。数组的地址应该存放在数组指针中
//int* parr[10];//这样写是指针数组
return 0;
}
3.2 &数组名 VS 数组名
int main()
{
int arr[10] = { 0 };
//arr;//数组名为首元素的地址
//&arr[0];//也代表首元素的地址
//&arr;//取出数组的地址
int(*p)[10] = &arr;
printf("%p\n", arr);//首元素地址 类型为:int*
printf("%p\n", &arr[0]);//首元素地址 类型为:int*
printf("%p\n", &arr);// 数组的地址 类型为:int(*)[10]
//三个printf打印的值相同
printf("%p\n", arr+1);//跳过一个元素的地址
printf("%p\n", &arr[0]+1);//跳过一个元素的地址
printf("%p\n", &arr+1);//跳过整个数组的地址
return 0;
}
int main()
{
数组名是首元素地址
//但是有2个例外
//1.sizeof(数组名)。这里的数组名是表示整个数组的。sizeof(数组名)计算的是整个数组的大小,单位为字节。
//2.&数组名。这里的数组名不是首元素地址,数组名依然表示整个数组。所以取出的是整个数组的地址。
int arr[10] = { 0 };
printf("%d\\n", sizeof(arr));
return 0;
}
int main(){ int* arr[10]; int*(*p)[10] = &arr; int** p2 = arr;//二级指针 return 0;}
3.3 数组指针的使用
///一维数组使用数组指针比较不方便,不建议使用void print1(int arr[], int sz){ int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); }}void print2(int* arr, int sz){ int i = 0; for (i = 0; i < sz; i++) { printf("%d ", *(arr+i)); }}//数组指针void print3(int (*parr)[10],int sz)//err{ int i = 0; for (i = 0; i < sz; i++) { printf("%d ",parr[i]);//parr[i] == *(parr+i) }}void print4(int(*parr)[10], int sz)//将一维数组看做只有一行的二维数组{ //*(parr + 0);//parr[0] int i = 0; for (i = 0; i < sz; i++) { //printf("%d ", parr[0][i]); //printf("%d ", (*(parr+0))[i]); printf("%d ", (*parr)[i]);//(*parr)相当于parr指向的数组的数组名 }}int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); //print1(arr,sz);//打印数组的内容 //print2(arr, sz); //print3(&arr, sz);//err print4(&arr, sz); return 0;}
///正确使用数组指针,二维数组可以受用数组指针void print1(int arr[3][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 ", arr[i][j]); } printf("\n"); }}void print2(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]); printf("%d ", *(*(p+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 }; //print1(arr,3,5); print2(arr,3,5);//arr为数组名,数组名是首元素地址,即二维数组的第一行(即一维数组)地址 return 0;}
int arr[5];//整型数组int* parr1[10];//整型指针数组//parr1是一个数组,有10个元素,每个元素都是一个整型指针int(*parr2)[10];//整型数组指针//parr2是一个指针,指向一个数组,数组有是个元素,每个元素都为整型。int(* parr3[10])[5];//整型数组指针数组。//parr3是一个数组,有10个元素,每个元素为是一个数组指针,每个数组指针指向的数组是5个元素的整型数组。
4. 数组传参和指针传参
//回顾int main(){ //字符指针 //char ch = 'w'; //char* p = &ch; //*p = 'b'; //const char* str = "abcdef"; //指针数组 //int* arr[10]; //char* arr2[4]; //数组指针 //int(*arr)[5]; //int* (*p)[5]; return 0;}
4.1 一维数组传参
void test(int arr[])//ok{}void test(int arr[10])//ok {}void test(int* arr)//ok{}void test2(int* arr[])//ok{}void test2(int* arr[20])//ok{}void test2(int** arr)//ok{}int main(){ int arr[10] = { 0 }; int* arr2[20] = { 0 }; test(arr); test2(arr2);}
4.2 二维数组传参
void test(int arr[3][5])//ok{}void test(int arr[][])//err{}void test(int arr[][5])//ok{}//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。void test(int* arr)//err{}void test(int* arr[5])//err{}void test(int(*arr)[5])//ok{}void test(int** arr)//err{}int main(){ int arr[3][5] = { 0 }; test(arr);//二维数组的首元素指的是第一行,即把二维数组想象为一维数组 //传过去的是二维数组第一行的地址,即一个一维数组的地址}
4.3 一级指针传参
void print(int * ptr,int sz){ int i = 0; for (i = 0; i < sz; i++) { printf("%d ", *(ptr + i)); }}int main(){ int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; int sz = sizeof(arr) / sizeof(arr[0]); print(p,sz); return 0;}
void test(int* p){}int main(){ int a = 10; test(&a); int arr[10] = { 0 }; test(arr); int* p1 = &a; test(p1); return 0;}
4.4 二级指针传参
void test(int** ppa){}int main(){ int a = 10; int* pa = &a; int** ppa = &pa; test(ppa); test(&pa); int* arr[5]; test(arr); return 0;}
5. 函数指针
函数指针变量 ----用来存放函数的地址。
&数组名–数组的地址
数组名–数组首元素的地址(2个例外)
函数名 --函数地址
&函数名–函数地址
int Add(int x, int y){ return x + y;}int main(){ //printf("%p\n", Add); //--函数地址 //printf("%p\n", &Add);//--函数地址 //int (*pf)(int,int) = &Add;//pf是用来存放函数地址,pf即为函数指针变量 //这个函数指针的类型为 int(*)(int,int) int (*pf)(int, int) = Add; //用法 int ret = Add(2, 3); printf("%d\n", ret); //ret = (*pf)(4, 5); ret = pf(4, 5); printf("%d\n", ret); return 0;}
//代码1 int mian(){ //代码是一次函数调用 //解析:将0强制类型转换为类型为void(*)()的这个函数的地址 //然后解引用0地址,就是去0地址处调用这个函数,这个函数无参,返回值为void (*( void (*)() ) 0)(); return 0;}//代码2int main(){ //这个代码是一次函数声明 //函数名为signal //函数2个参数,一个为int类型,另一个为void(*)(int)的函数指针类型 //函数返回类型为void(*)(int)的函数指针类型 void ( *signal(int, void(*)(int)) ) (int);//函数指针 typedef void(*pfun_t)(int); pfun_t signal2(int, pfun_t); //简化后的代码2 return 0;}
6. 函数指针数组
int Add(int x, int y)//int (*)(int, int){ return x + y;}int Sub(int x, int y)//int (*)(int, int){ return x - y;}int Mul(int x, int y)//int (*)(int, int){ return x * y;}int Div(int x, int y)//int (*)(int, int){ return x / y;}int mian(){ int* arr[10];//整型指针的数组 //函数指针的数组-存放函数指针的数组 //int (*pf1)(int, int) = Add; //int (*pf2)(int, int) = Sub; //int (*pf3)(int, int) = Mul; //int (*pf4)(int, int) = Div; //pfArr是一个函数指针数组 int (*pfArr[4])(int, int) = { Add,Sub,Mul,Div }; return 0;}
/计算器实现int Add(int x, int y)//int (*)(int, int){ return x + y;}int Sub(int x, int y)//int (*)(int, int){ return x - y;}int Mul(int x, int y)//int (*)(int, int){ return x * y;}int Div(int x, int y)//int (*)(int, int){ 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");}//int main()//{// int input = 0;// do // {// int x = 0;// int y = 0;// int ret = 0;// menu();// printf("请选择>");// scanf("%d", &input);// // switch (input)// {// case1:// printf("请输入俩个操作数>");// scanf("%d %d", &x, &y);// ret = Add(x,y);// printf("%d\n", ret);// break;// case2:// printf("请输入俩个操作数>");// scanf("%d %d", &x, &y);// ret = Sub(x, y);// printf("%d\n", ret);// break;// case3:// printf("请输入俩个操作数>");// scanf("%d %d", &x, &y);// ret = Mul(x, y);// printf("%d\n", ret);// break;// case4:// printf("请输入俩个操作数>");// scanf("%d %d", &x, &y);// ret = Div(x, y);// printf("%d\n", ret);// break;// case0:// printf("退出\n");// break; // default:// printf("输入错误\n");// break; }// } while (input); return 0;//}//int main()//{// int input = 0;// do// {// int x = 0;// int y = 0;// int ret = 0;// menu();// printf("请选择>");// scanf("%d", &input);// int (*pfArr[5])(int, int) = { 0,Add,Sub,Mul,Div }; if (input == 0)// {// printf("退出\n");// }// else if (input >= 1 && input <= 4)// {// printf("请输入俩个操作数>");// scanf("%d %d", &x, &y);// ret = pfArr[input](x, y);// printf("%d\n", ret);// }// else// {// printf("输入错误\n");// }// } while (input); return 0;//}void Calc(int(*pf)(int, int)){ int x = 0; int y = 0; int ret = 0; printf("请输入俩个操作数>"); scanf("%d %d", &x, &y); ret = pf(x, y); printf("%d\n", ret);}int main(){ int input = 0; do { menu(); printf("请选择>"); scanf("%d", &input); switch (input) { case1: Calc(Add); break; case2: Calc(Sub); break; case3: Calc(Mul); break; case4: Calc(Div); break; case0: printf("退出\n"); break; default: printf("输入错误\n"); break; } } while (input); return 0;}
7. 指向函数指针数组的指针
int arr[10];//整型数组int(*p)[10] = &arr;//p为一个指向(整型数组)的指针int* arr[10];//整型指针数组int* (*p)[10] = &arr;//p为一个指向(整型指针数组)的指针int Add(int x, int y){ return x + y;}(int)(*pf)(int, int) = Add;//pf为一个函数指针(int)(*pfArr[5])(int, int)//pfArr为一个函数指针数组(int)(*(*ppfArr)[5])(int, int) = &pfArr; //ppfArr为一个指向(函数指针数组)的指针
8. 回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一
个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该
函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或
条件进行响应。
int Add(int x, int y)//int (*)(int, int){ return x + y;}int Sub(int x, int y)//int (*)(int, int){ return x - y;}void Calc(int(*pf)(int ,int)){ int ret = pf(3, 5); printf("%p\n", pf); //printf("%d\n", ret);}int main(){ //Calc(Add); Calc(Sub); printf("%p\n", Sub); return 0;}
qsort -库函数void qsort(void* base, //地址 size_t num, //待排序的元素个数 size_t width, //一个元素的大小,单位为字节 int(__cdecl* compare)(const void* elem1, const void* elem2));//compare指向的是(排序时用来比较两个元素的函数)
int main(){ int a = 10; float f = 5.5f; //char* p1 = &a; //int* //char* p2 = &f; //float* void* p1 = &a; //int* void* p2 = &f; //float* //void* - 无具体类型指针,可以接收任意类型的地址。缺点:不能进行指针运算,不能解引用 return 0;}
//比较2个整型函数int cmp_int(const void* e1, const void*e2){ return *(int*)e1 - *(int*)e2;}void print_arr(int arr[], int sz){ int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); }}void test1(){ int arr[] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp_int); //打印 print_arr(arr, sz);}struct Stu{ char name[20]; int age;};int cmp_by_name(const void*e1, const void*e2){ return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);}int cmp_by_age(const void* e1, const void* e2){ return ((struct Stu*)e1)->age -((struct Stu*)e2)->age;}void test2(){ struct Stu s[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10}}; int sz = sizeof(s) / sizeof(s[0]); //按照名字排序 //qsort(s, sz, sizeof(s[0]), cmp_by_name); //按照年龄来排序 qsort(s, sz, sizeof(s[0]), cmp_by_age);}void Swap(char* buf1, char* buf2, int width){ int i = 0; for (i = 0; i < width; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; }}//使用回调函数实现一个通用的冒泡排序函数void BubbleSort(void* base, size_t num, size_t width, int (*cmp)(const void*, const void*)){ size_t i = 0; //趟数 for (i = 0; i < num - 1; i++) { //比较的对数 size_t j = 0; for (j = 0; j < num - 1 - i; j++) { //base[j] ==> *(base+j) if (cmp((char*)base+j*width, (char*)base+(j+1)*width)>0) { //交换 Swap((char*)base + j * width, (char*)base + (j + 1) * width, width); } } }}//测试自定义的BubbleSort() 排序数组;void test3(){ int arr[] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); BubbleSort(arr, sz, sizeof(arr[0]), cmp_int); //打印 print_arr(arr, sz);}//测试自定义的BubbleSort() 排序结构体void test4(){ struct Stu s[3] = { {"zhangsan", 15}, {"lisi", 30},{"wangwu", 10} }; int sz = sizeof(s) / sizeof(s[0]); //按照名字排序 //BubbleSort(s, sz, sizeof(s[0]), cmp_by_name); //按照年龄来排序 BubbleSort(s, sz, sizeof(s[0]), cmp_by_age);}int main(){ //测试排序整型数组 //test1(); // //排序结构体数据 //test2(); //测试自定义的BubbleSort(); //test3(); test4(); return 0;}
9. 指针和数组面试题的解析
int main(){ int a[] = { 1,2,3,4 }; printf("%d\n", sizeof(a));//数组名a单独放在sizeof内部,数组名表示整个数组,计算的是整个数组的大小 printf("%d\n", sizeof(a + 0));//a表示首元素的地址,a+0还是首元素的地址,地址的大小是4/8字节 printf("%d\n", sizeof(*a)); //a表示首元素的地址,*a 就是首元素 ==> a[0] ,大小就是4 *a <==> *(a+0) <==> a[0] printf("%d\n", sizeof(a + 1));//a表示首元素的地址,a+1是第二个元素的地址,大小就是4/8 printf("%d\n", sizeof(a[1])); //a[1] 就是第二个元素 - 4 printf("%d\n", sizeof(&a)); //&a - 数组的地址 - 4/8 - int(*)[4] printf("%d\n", sizeof(*&a));//*&a-&a是数组的地址,对数组的地址解引用拿到的是数组,所以大小是16 printf("%d\n", sizeof(a));//16 printf("%d\n", sizeof(&a + 1));//&a是数组的地址,&a+1是数组的地址+1,跳过整个数组,虽然跳过了数组,还是地址 4/8 printf("%d\n", sizeof(&a[0]));//4/8 printf("%d\n", sizeof(&a[0] + 1));//第二个元素的地址 4/8 return 0;}
数组名:
1.sizeof(数组名)- 数组名表示整个数组,计算的是整个数组的大小
2.&数组名 - 数组名表示整个数组,取出的是整个数组的地址
除此之外,所有的数组名均表示数组首元素的地址
int main(){ char arr[] = { 'a','b','c','d','e','f' };//[a,b,c,d,e,f] printf("%d\n", sizeof(arr));//数组大小 6 printf("%d\n", sizeof(arr + 0));// 数组首元素地址 4/8 printf("%d\n", sizeof(*arr));// a的大小 1 printf("%d\n", sizeof(arr[1]));//b的大小 1 printf("%d\n", sizeof(&arr));//数组地址的大小 4/8 printf("%d\n", sizeof(&arr + 1));//数组地址+1的大小 4/8 printf("%d\n", sizeof(&arr[0] + 1)); //数组首元素地址+1的大小 4/8 printf("%d\n", strlen(arr));//随机值 printf("%d\n", strlen(arr + 0));//随机值 printf("%d\n", strlen(*arr));// *arr - 'a' - 97 程序以为传进来的a的ASCII值97就是地址,会非法访问或程序崩溃 -err printf("%d\n", strlen(arr[1]));//同理上 printf("%d\n", strlen(&arr));// 随机值 printf("%d\n", strlen(&arr + 1));//随机值 printf("%d\n", strlen(&arr[0] + 1));//随机值 char arr[] = "abcdef";//[a,b,c,d,e,f,\0] printf("%d\n", sizeof(arr));//整个数组大小 7 printf("%d\n", sizeof(arr + 0));// 数组首元素地址 4/8 printf("%d\n", sizeof(*arr));// a的大小 1 printf("%d\n", sizeof(arr[1]));//b的大小 1 printf("%d\n", sizeof(&arr));//数组地址的大小 4/8 printf("%d\n", sizeof(&arr + 1));//数组地址+1的大小 4/8 printf("%d\n", sizeof(&arr[0] + 1)); //数组首元素地址+1的大小 4/8 printf("%d\n", strlen(arr));//6 printf("%d\n", strlen(arr + 0));//6 printf("%d\n", strlen(*arr));//*arr - 'a' - 97 程序以为传进来的a的ASCII值97就是地址,会非法访问或程序崩溃 -err printf("%d\n", strlen(arr[1]));//同理上 printf("%d\n", strlen(&arr));//6 printf("%d\n", strlen(&arr + 1));//随机值 printf("%d\n", strlen(&arr[0] + 1));//5 const char* p = "abcdef"; printf("%d\n", sizeof(p));//p是指针变量,存放的是地址,a的地址 4/8 printf("%d\n", sizeof(p + 1));//p+1是字符b的地址 4/8 printf("%d\n", sizeof(*p));//1 printf("%d\n", sizeof(p[0]));//p[0]->*(p+0) 1 printf("%d\n", sizeof(&p));//4/8 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));//错误 printf("%d\n", strlen(p[0]));//错误 printf("%d\n", strlen(&p));//随机值 printf("%d\n", strlen(&p + 1));//随机值 printf("%d\n", strlen(&p[0] + 1));//5 //二维数组 int a[3][4] = { 0 }; //a为二维数组数组名 a[0]为第一行数组名 a[1]为第二行数组名 a[2]为第三行数组名 printf("%d\n", sizeof(a));//48 printf("%d\n", sizeof(a[0][0]));//4 printf("%d\n", sizeof(a[0]));//a[0]是第一行的数组名,单独放在sizeof内部 ,表示第一行整个数组 16 printf("%d\n", sizeof(a[0] + 1));// a[0]为首元素的地址 a[0]+1 第一行第二个元素的地址 4/8 printf("%d\n", sizeof(*(a[0] + 1)));//4 printf("%d\n", sizeof(a + 1));//a表示首元素的地址,即第一行的地址,+1之后表示第二行的地址 4/8 int(*)[4] printf("%d\n", sizeof(*(a + 1)));//16 printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]拿到第一行的地址 +1为第二行的地址 4/8 printf("%d\n", sizeof(*(&a[0] + 1)));//16 printf("%d\n", sizeof(*a));//a为首元素地址,第一行的地址 *a拿到首元素,第一行 16 printf("%d\n", sizeof(a[3]));//a[3]若存在表示第四行 //总结: 数组名的意义: // 1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。 // 2. & 数组名,这里的数组名表示整个数组,取出的是整个数组的地址。 // 3. 除此之外所有的数组名都表示首元素的地址。 // int arr[3][4]; // 二维数组的数组名为a sizeof(a) , &(a) a - 二维数组首元素地址,即第一行地址 // 第1行的数组名为a[0] sizeof(a[0]), &(a[0]) a[0] - 第1行第1个元素的地址 // 第2行的数组名为a[1] sizeof(a[1]), &(a[1]) a[1] - 第2行第1个元素的地址 // 第3行的数组名为a[2] sizeof(a[2]), &(a[2]) a[2] - 第3行第1个元素的地址 // 数组名表示整个数组 除此之外 return 0;}
//前端和后端
//前端:能看见
// 网页 小程序 APP pc客户端 写前端的程序来展示/显示
//后端:看不见
// 服务器端程序
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;}struct Test{ int Num;// 4 char* pcName;// 4/8 short sDate;// 2 char cha[2];// 1*2=2 short sBa[4];// 2*4=8}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?//已知结构体Tset类型的变量大小为20字节int main(){ p = (struct Test*)0x100000; printf("%p\n", p + 0x1);// 00100014 printf("%p\n", (unsigned long)p + 0x1);// 00100001 printf("%p\n", (unsigned int*)p + 0x1);// 00100004 return 0;}
int main(){ int a[4] = { 1, 2, 3, 4 };//小端存储 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 int* ptr1 = (int*)(&a + 1); //&a取出数组地址,+1后跳过整个数组,然后强制类型转换为int* int* ptr2 = (int*)((int)a + 1);//a表示首元素地址,强制转换为int然后+1,其实就是地址数值+1,再强制转换为int*,指向的是第一个00到向后4个字节 printf("%x,%x", ptr1[-1], *ptr2);//ptr[-1] == *(ptr-1) --- 4 return 0;}
int main(){ int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式 1 3 5 0 0 0 int* p; p = a[0];//a[0]表示第一行数组名,这时表示首元素1的地址 printf("%d", p[0]);//p[0] == *(p+0) == *P return 0;}
int main(){ int a[5][5]; int(*p)[4]; p = a;//a表示首元素地址,即第一行的地址 int(*)[4] printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); //地址相减 差值为元素个数 //%p打印 -4 的补码直接被解析 //%d打印 -4 的补码转成反-原 打印 return 0;}
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)); return 0;}
int main(){ char* a[] = { "work","at","alibaba" }; char** pa = a; pa++; printf("%s\n", *pa); return 0;}
int main(){ char* c[] = { "ENTER","NEW","POINT","FIRST" }; char** cp[] = { c + 3,c + 2,c + 1,c }; char*** cpp = cp; printf("%s\n", **++cpp);//point printf("%s\n", *-- * ++cpp + 3);//er printf("%s\n", *cpp[-2] + 3);//st printf("%s\n", cpp[-1][-1] + 1);//ew return 0; // ++ -- 会改变指针指向位置}
直接退出所有循环 1.return 0;
2.goto 语句