C语言16 指针

C语言16 指针 指针数组本质上是一个数组只不过这个数组里的每个元素都是一个指针变量。存储的是地址。定义类型名 *数组名[数组大小];[]的优先级高于*所以arr先和[]结合表示它是一个数组。然后再和*结合表示数组中的元素是指针。类型名表示指针所指向的数据的类型。#includestdio.h int main(int argc,char **argv) /*{ char *pstr[4]{hello,ok,123,aaa}; //读取数据 int i0; for(i0;i4;i) { printf(i: %d %s\n,i,pstr[i]); } //因为指向了常量所以没法修改 pstr[0][0]pstr[0][0]1; for(i0;i4;i) { printf(i: %d %s\n,i,pstr[i]); } return 0; }*/ { char strs[4][100]{hello,ok,123,aaa}; //指向了数组中的字符串可读可写 char *pstr[4]{strs[0],strs[1],strs[2],strs[3]}; //指针数组的初始化让数组中的每个指针指向二维字符数组 strs 的每一行。 int i 0; for(i0;i4;i) { printf(i: %d %s\n,i,pstr[i]); } pstr[0][0]pstr[0][0]1; pstr[1][0]pstr[1][0]1; pstr[2][0]pstr[2][0]1; pstr[3][0]pstr[3][0]1; for(i0;i4;i) { printf(i: %d %s\n,i,pstr[i]); } return 0; }字符串分割#includestdio.h #includestring.h int main(int argc,char **argv) { char *pstr[3]{NULL};//3个指针全部初始化为NULL char str[100]how are you; char *tmp str;//赋值时只写变量名地址,str是地址数组名退化为地址 pstr[0]str; int i 1; //pstr[0] 已经存储了第一个单词的起始位置 //所以下一个单词应该从 pstr[1] 开始存放 //因此 i 初始化为 1 while(*tmp) { if(*tmp! ) { } else { *tmp \0; pstr[i]tmp1;//让指针数组的下一个元素指向下一个单词的开始 } tmp; } for(i0;i3;i) { printf(%d %s\n,i,pstr[i]); } return 0; }数组指针对一维数组名执行 取地址操作() , 地址值 不变 类型升级为指向整个数组的指针对数组指针 执行 解引用操作 (*) , 地址值 不变, 类型降为指向第一个元素的指针应用1 需要和二维数组配合使用2 把二维数组作为参数的时候在定义被调函数需要声明 参数的数据类型会用到。#if 0 int a[5] {1, 2, 3, 4, 5}; // int []-- int * printf(a addr %p\n, a); printf(a[0] addr %p\n, a[0]); printf(a[1] addr %p\n, a[1]); printf(a[2] addr %p\n, a[2]); printf(*a addr %d\n, *a); // int printf(a[0] addr %d\n, a[0]); // int printf(*(a1) addr %d\n, *(a 1)); // int printf(a[1] addr %d\n, a[1]); // int printf(a1 addr %p\n, a 1); // int * printf( a %p\n, a); // 数组指针 printf(a1 %p\n, a 1); int(*p)[5] a; // int (*p)[5] 数组指针 int* p[5] // int * p1[5] a; #endif int array2[4][4] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; int(*p2)[4] array2; printf(array2 is addr%p\n, array2); // int [4][4] - int (*)[4] 1 -16byte printf(array2[0] is addr%p\n, array2[0]);// int * 1 4byte printf(array2[0][0] is addr%p\n, array2[0][0]);// int * 1 4byte printf(array2[0][0] is addr%d\n, array2[0][0]); // int printf(a[1][2] %d\n,array2[1][2]); // printf(a[1][2] %d\n,*(array2[1]2)); printf(a[1][2] %d\n,*(*(array21)2)); printf(p2[1][2] %d\n,p2[1][2]); printf(p2[1][2] %d\n,*(p2[1]2)); printf(p2[1][2] %d\n,*(*(p21)2)); printf(a[0] %p\n,array2[0]); printf(a[1] %p\n,array2[1]); printf(p2 %p\n,p2); printf(p21 %p\n,p21); int array2[4][4] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; array2 类型 -》 指针 -》 int [4][4] int(*)[4] 列是4 1 sizeof(int) *4(列) array2[0] -- 指针 -》 int * 第一行的首元素的地址 array2[0][0] array2[0][0] - int - 数据 int(*p2)[4] array2; p2 - 类型 int(*)[4] 1 sizeof(int) *4(列) p2[0] - 类型 int* 第一行的首元素的地址 array2[0][0] p2[0][0] - int - 数据 p2[1] *(p21) 下标运算符 和 解引用运算符的关系。二级指针指向指针的指针。 在定义指针变量的时候会开辟8个自己的空间 。指针变量本身也是有内存地址的。对一级指针取地址操作就会获得二级指针。需要解引用两次 可以访问到数数据。想改普通变量的值 → 传一级指针想改指针变量的值 → 传二级指针1. 如果在被调函数中需要修改指针的指向(指针本身)。就需要传递二级指针2 如果在被调函数中需要修改指针指向的内容(指针指向的变量数据)。就需要传递一级指针int a 10; int *p a; // 一级指针 int **pp p; // 二级指针存 p 的地址void fun2(char ** arg_p) // 二级指针 { static char str[10]hello; *arg_p str; // 可以修改主调的参数 } int main(int argc, char **argv) { char *p NULL; fun2(p); printf(p is %s\n,p); return 0; }二级指针作为参数传递作为参数传递的时候char** 和 char * [] 是兼容类型int show_str( char * str[],int size) { int i 0 ; for(i0;isize;i) { printf(%d %s\n,i,str[i]); } return 0; } int show_str2( char **str,int size) // 二级指针,可以接收 char*[] 传递过来的参数类型兼容 { int i 0 ; for(i0;isize;i) { printf(%d %s\n,i,str[i]); } return 0; } int main(int argc, char **argv) { char *str[5]{hello,ok,how,are,you};// char * [5] str[0] -char* show_str2(str,5); return 0; }main命令参数// ./a.out 1 5 // argv[0] argv[0] argv[2] int main(int argc, char *argv[]) //int main(int argc, char **argv) { //argc 命令行参数的个数 3 //argv 参数的具体内容 printf(argc is %d\n,argc); int i 0 ; for(i0;iargc;i) { printf(%d %s\n,i,argv[i]); } if(argc3) { printf(usage:./a.out num1 num2\n); return 1; } int sum atoi(argv[1]) atoi(argv[2]); //atoi() 函数ASCII to Integer将字符串转换成整数 printf(sum is %d\n,sum); return 0; }const 指针和变量const 表示常量不变的意思。 或只读修饰。一旦初始化值不能改变必须在定义时初始化除非是 extern 声明本质是只读变量不是真正的常量C语言中const char* p1; // const 在 * 左边 → 指向的数据不可变 char const* p2; // 同上等价写法 char* const p3; // const 在 * 右边 → 指针本身不可变 const char* const p4; // 两个 const → 都不可变voidvoid 空、无、没有它表示没有类型或空类型。空白空着不能定义变量 空间大小位置用在函数的参数 返回值 。返回值为空 函数调用结束后表达式没有值作为参数时候 表示函数一个参数也没有 。 可以省略(和编译器有关).void fun(void) { }void* 通用指针void*是一个通用指针可以指向任何类型的数据。int a 10; char c A; float f 3.14; void* p; // 通用指针 p a; // ✅ 可以指向 int p c; // ✅ 可以指向 char p f; // ✅ 可以指向 float在被调函数中需要对 void* 指针进行强制类型转换。void* 类型的指针存储着 实参传递过来的地址。 但是不能进行 解引用操作因为没有void类型的变量。int a 10; void* p a; // ❌ 错误不能直接解引用 void* // printf(%d\n, *p); // 编译错误 // ✅ 正确必须先强制转换成具体类型 printf(%d\n, *(int*)p); // 转换成 int* 再解引用void* mymemcpy(void* dest, const void* src, int size) { int i 0; char* pdest (char*)dest; // 需要强制类型转换 char* psrc (char*)src; for (i 0; i size; i) { // dest[i] src[i]; *pdest *psrc; // 基类型是char 偏移量是 1 byte pdest; psrc; } return dest; }