 指针的常见操作)
指针的常见操作指针变量有两方面的意思:一个指针指向的内容(数据值一级)指针变量本身存储的数据 (地址值)#include stdio.h int main() { int a 10; int b 0 ; int c 50; int *p NULL; int *q NULL; p a; // 对指针变量本身进行修改 // 对指针指向的数据 进行操作 b *p ;// 通过地址获得地址中数据, 相当与是对 a变量的读取 *p 20;// 把需要写入的数据通过地址写入对应的内存 对a 变量的写入 p c; // p变量本身发生变化与c变量关联 b *p; // 对c变量读取操作 *p 10; //对 c变量的写入操作 q p;// 把p指向的地址赋值给q。pq 指向同一个变量了c。 return 0; }赋值运算符的左右值p做 左值 对指针变量本身进行修改 存储某个变量的地址p做 右值 把p指向的地址赋值给另外一个指针。p另一个 指向同一个变量了。*p做 左值 向指针指向的变量 写入数据*p做 右值 读出向指针指向的变量的数据指针作为参数 传参函数传递参数1. 值传递 在主调函数中实参在被调函数中形参。 形参可以读出实参的数据。但是不能修改实参的值。2.地址传递。 在主调函数中实参; 在被调函数中形参。 形参可以通过间接访问的方式读写实参的数据。实参和形参都是指针。这两个指针中存储的地址值同一个变量的地址。#include stdio.h int func(int a, int b, int* sum, int* sub) { *sum a b; *sub a - b; return 0; } int main(int argc, char** argv) { int a 10; int b 20; int sum 0; int sub 0; func(a, b, sum, sub); int *pa NULL; printf(a is %d b is %d sum:%d sub:%d\n, a, b, sum, sub); return 0; }函数使用指针作为参数1. 第一种情况需要形参修改实参的情况。需要被调函数修改主调函数中数据的值。2. 函数的返回值只有一个。 在被调函数中需要返回多个数据的话就需要传递值指针。因为在被调函数中可以修改主调函数的参数的只。void swap(int arg_a,int arg_b)//值传递 { int t arg_a; arg_a arg_b; arg_b t; } void swap2(int * pa,int *pb) //地址传递 { int t *pa; *pa *pb; *pb t; } int main() { int a 1; int b 2; //swap(a,b); swap2(a,b); printf(a is %d,b is %d\n,a,b); // 指针可以指向 任意0-4G地址 。但是不一定能读写内存有保护机制 int * p (int*)0x2000; }指针和数组的关系1. 数组名是一个指向数组第一元素的指针常量(指针本身的值不能发生变化。 指针是保存地址的变量指针保存的地址不能发生变化)。2. 数组名的类型 int a[] ; 类型 int [] int [ ] ≈ int * ;int [ ] ≈ int * ; c语言中兼容类型。大部分可以相互替换但是有例外。不同点1. sizeof()int* -- 8byte int a[20] - 20*sizeof(int) 80byte2. 在执行 取地址操作int*p - - int **(二级指针地址的地址)int a[10] - - int (*p)[10] (数组指针)int a[10] ; 对于数组名a 来说可以把他想成一个指针变量 。 本质 a 是数组中第一个元素地址的别名。一维数组做参数// int fill_array(int a[],int size) int fill_array(int *a, int size) { int i 0; // for(i0;isize;i) // { // a[i] rand()%50; // } for (i 0; i size; i) { //(*a)i rand()%50; *(a i) rand() % 50; } return 0; }一维字符数组做参数#include stdio.h //void show_str(char a[]) void show_str(char *a) { int i 0 ; // while(\0!a[i]) // { // printf(%c,a[i]); // i; // } // printf(\n); // while(\0!*(ai) ) // { // printf(%c,*(ai)); // i; // } // printf(\n); while(\0!*a) { printf(%c,*(a)); } printf(\n); } int main(int argc, char **argv) { char str[100]{0};// char [] -- char * printf(input str); gets(str); show_str(str); return 0; }字符指针常见错误#include stdio.h int main(int argc, char **argv) { //char *p hello; // hello 在内存中只用一份只能读取不能修改 char p[] hello; // char [] 开辟空间会把hello字符串常量复制一份给数组。 printf(%s\n, p); *(p 0) e; // 如果是指针操作是错误不能修改常量 p[0] e; // 如果是数组操作是对的修改的是数组里的内容不是字符串常量 printf(%s\n, p); return 0; }野指针#include stdio.h void swap(int *a,int *b) { int *t; // int t; *t *a; // t *a; // *t ,是野指针 *a *b; *b *t; } int main(int argc, char **argv) { int a 10; int b 20; swap(a,b); /* */ return 0; }函数指针指针函数1. 指针函数函数的返回值是 指针类型 。char *strcpy(char *dest, const char *src);strcpy 这个函数的返回值就是一个指针。 成功指针指向 dest。1 不能返回是局部作用域的指针。2 希望函数可以连续调用。 在同一个语句里面。 strcpy(str1,strcpy(str3,str2));3希望返回一端内存区域 (数组堆空间)。#include stdio.h #if 0 int * func1() // 错的 { int a[10]{1,2,3,4,5,6};// 0x2000 这个数组是个局部变量 printf(a addr %p\n,a[0]); return a;// a a[0] 不要返回局部变量 } int * func2() //对的 { static int a[10]{1,2,3,4,5,6};// 0x2000 printf(a addr %p\n,a[0]); return a;// a a[0] } int main(int argc, char **argv) { int *p NULL; p func2(); printf(main p addr %p\n,p); printf(p[0] %d\n,p[0]); return 0; } //............................. int * fun3(int *a,int size) { a[1]a[3]a[5]20; return a; } int main(int argc, char **argv) { int a[10]{0};// 0x2000 int * p fun3(a,10); printf( a[1]:%d a[3]:%d\n,a[1],a[3]); printf( p[1]:%d p[3]:%d\n,p[1],p[3]); return 0; }#include stdio.h #include string.h int mystrcpy(char *dst, char *src) { while (*src) { *dst *src; dst; src; } *dst\0; return 0; } char* mystrcpy2(char *dst, char *src) { char * tmp dst; while (*src) { *dst *src; dst; src; } *dst\0; return tmp; } char* mystrcat(char *dst,char * src) { char* tmp dst; while(*dst) { dst; } while(*src) { *dst*src; src; dst; } *dst \0; return tmp; } int main(int argc, char **argv) { char str1[100]hello; char str2[100]ok; char str3[100]{0}; // char *strcpy(char *dest, const char *src); //strcpy(str1,strcpy(str3,str2));// strcpy(str3,str2); str3 , strcpy(str1,str3); //printf(str1 is %s\n,str1); // mystrcpy2(str1,mystrcpy2(str3, str2)); // printf(str1 is %s\n,str1); mystrcat(str3,mystrcat(str1,str2)); printf(str3 is %s\n,str3); return 0; }2. 函数指针前面介绍的指针基本都是指数据。函数指针指向一个函数。本质指针变量函数名是地址值。里面储存的代码对数据进行加减乘除操作的。目的避免代码的重复。 方便后期代码的扩展。函数功能的解耦合。回调函数一个函数被当作参数 传递给另外一个函数。 被传递这个参数(函数指针回调函数)被动调用。主调函数只是传参(函数)语法 int add(int a, int b) // int (*) (int,int) { return a b; } int main(int argc, char **argv) { int (*p)(int, int) add; // p 函数指针。 add 不能写成add(), 不是对add函数的调用 int a 10; int b 20; int ret 0; ret add(a, b); printf(add() is %d\n, ret); ret p(a, b); // 通过函数指针 对函数的调用 printf(p() is %d\n, ret); return 0; }#include stdio.h #include stdlib.h #include time.h int fill_array(int *a, int size) { int i 0; // for(i0;isize;i) // { // a[i] rand()%50; // } for (i 0; i size; i) { //(*a)i rand()%50; *(a i) rand() % 50; } return 0; } int find_num3(int* a,int size) { for(size_t i0;isize;i) { if(0 a[i]%3) { printf(%d\n,a[i]); } } return 0; } int find_num5(int* a,int size) // int (*) (int*,int) { // int a; int ; int* p ;int* for(size_t i0;isize;i) { if(0 a[i]%5) { printf(%d\n,a[i]); } } return 0; } //............................................... int div3(int num) // div3 - int (*) (int) { return 0 num %3; } int div5(int num) // div3 - int (*) (int) { return 0 num %5; } void find_num(int* a,int size, int (*fun) (int) ) { for(size_t i0;isize;i) { if( fun(a[i])) // if( div5(a[i])) { printf(%d\n,a[i]); } } } int main(int argc, char **argv) { srand(time(NULL)); int a[10]{0}; fill_array(a,10); //find_num3(a,10); find_num(a,10,div5); // div5(); return 0; }typedef 关键字取别名 给数据类型取别名1. 普通数据类型 去别名typedef 老数据类型名 新数据类型名 typedef unsigned char u8; typedef unsigned short u16; typedef char s8; int main(int argc, char **argv) { u8 a; // unsigned char u16 b; // unsigned short s8 c; // char return 0; }2. 简化函数指针的写法typedef int* (*PFUN)(int ,int ,char* ); // int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) // { // return NULL; // } // int func2(int a,int b, int* (*pfun)(int ,int ,char* )) // { // return 0; // } int* func(int a,int b ,char* c) // int* (*)(int ,int ,char* ) { return NULL; } int func2(int a,int b, PFUN pfun) { char str[]{0}; pfun(1,2,str); return 0; }3.和结构体有关晚些介绍