11-指针

作者: Andy_Livings | 来源:发表于2020-05-29 11:45 被阅读0次

    一、指针

    1.指针的重要性
    指针是C语言中非常重要的数据类型,如果你说C语言中除了指针,其他你都学得很好,那你干脆说没学过C语言。

    2.小需求

    • void change(int n)函数调用完毕后,改变实参的值
    • 分析:修改实参的值->找到存储空间->地址

    二、指针变量的定义

    1.定义的格式
    • 类名标识符 *指针变量名;
    int *p;
    
    2.先定义后赋值
    • 简单取值
    int a = 10;
    int *p;
    p = &a;
    printf(“%d”, *p);
    
    • 简单改值
    *p = 9;
    
    3.定义的同时赋值
    int a = 10;
    int *p = &a;
    
    4.实现修改实参
    5.注意点
    • int *p; p = 1000;
    • int *p; *p = 100;
    • int *p; *p = &a;
    • %p输出指针里面存储的地址值
    • 其他指针类型说明,比如float *p; char *p;
    • 不能乱用类型,比如int a = 10; float *p = &a;
    6.清空指针
    p = 0;
    p = NULL;
    

    三、指针实例

    1.void swap(char *a, char *b)  (注意temp=a;  a = b; b = temp;)
    2.int sumAndMinus(int a, int b, int *minus)
    

    四、指针探究

    1.指针变量所占用的存储空间
    2.为何指针变量要分类型?
    int i = 2;
    char c = 1;
    int *p = &c;
    printf(“%d”, *p);
    

    五、指针与数组

    1.指向一维数组元素的指针
    2.用指针遍历一维数组元素
    • 先遍历char数组(‘i’,’t’),再遍历int类型数组
    • (p+i)和(p++)的区别
    • a+i和a++
    • p[0]、p[1]
    3.习题

    1>设计一个函数:int arraySum(int a[], int n),求一维数组a前n个数的和。现在利用int *p替换int a[]

    六、指针与字符串

    1.字符串回顾
    char s[] = “hello”;
    
    2.其他定义字符串的方式
    char *s = “hello”;
    或者
    char *s;
    s = “hello”;
    
    3.两种定义方式的区别
    • 内存分析
    • 画图分析
    • 常量和变量字符串的区别
    • 常量的内存地址查看
    4.习题

    1>编写一个int string_len(char *s),返回字符串s的字符长度

    七、返回指针的函数

    • 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的
    • 返回指针的函数的一般形式为:类型名 * 函数名(参数列表)

    八、指向函数的指针

    1.为什么指针可以指向一个函数?

    函数作为一段程序,在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。函数有自己的地址,那就好办了,我们的指针变量就是用来存储地址的。因此,可以利用一个指针指向一个函数。其中,函数名就代表着函数的地址。

    2.指向函数的指针的定义

    定义的一般形式:函数的返回值类型 (*指针变量名)(形参1, 形参2, ...);

    3.使用注意
    • 由于这类指针变量存储的是一个函数的入口地址,所以对它们作加减运算(比如p++)是无意义的
    • 指向函数的指针变量主要有两个用途:
    • 调用函数
    • 将函数作为参数在函数间传递

    九、指针总结

    一、指针变量的定义
    1. 格式:变量类型 *指针变量名;
    2. 举例:int *p;   char *p2;
    3. 注意:定义变量时的*仅仅是指针变量的象征
    
    二、利用指针变量简单修改其他变量的值
    1.指向某个变量
    int a;
    
    int *p;
    p = &a;
    或者
    int *p = &a;
    
    2.修改所指向变量的值
    *p = 10;
    
    3.在函数内部修改外面变量的值
    int a = 10;
    change(&a);
    
    void change(int *n)
    {
        *n = 20;
    }
    
    三、指针与数组
    1.将数组当做函数参数传入时,会自动转为指针
    
    四、指针与字符串
    1.定义字符串的2种方式
    1> 利用数组
    char name[] = "zhang san";
    * 特点:字符串里面的字符是可以修改的
    * 使用场合:字符串的内容需要经常修改
    
    2> 利用指针
    char *name = "zhang san";
    * 特点:字符串其实是一个常量字符串,里面的字符是不能修改
    * 使用场合:字符串的内容不需要修改,而且这个字符串经常使用
    
    2.定义字符串数组
    1> 利用二维字符数组
    char names[2][10] = {"jack", "rose"};
    
    2> 利用指针数组
    char *names[2] = {"jack", "rose"};
    



    十、程序实现

    01-指针

    void change_value(int *n);
    void pointer(void) {
        
        // 变量类型  变量名;
        // 格式:变量类型 *变量名;
        // 定义了一个指针变量p
        // 指针变量只能存储地址
        // 指针就一个作用:能够根据一个地址值,访问对应的存储空间
        // 指针变量p前面的int:指针变量p只能指向int类型的数据
        int *p;
        int a = 90;
        // 指针变量p指向了变量a
        p = &a;
        *p = 10;
        a = 20;
        
        printf("*p = %d\n", *p);
        //printf("a = %d\n", a);
        
        /*
         int a1 = 90;
         change_value(&a1);
         printf("a1 = %d\n", a1);
         */
    }
    
    void change_value(int *n) {
        *n = 10;
    }
    

    02-指针的使用注意

    void use_pointers_note(void) {
        
        /* 不建议的写法, int *p只能指向int类型的数据
         int *p;
         double d = 10.0;
         p = &d;
         */
        
        /* 指针变量只能存储地址
         int *p;
         p = 200;
         */
        
        /* 指针变量未经过初始化,不要拿来间接访问其他存储空间
         int *p;
         printf("%d\n", *p);
         */
        
        int a = 10;
        /*
         int a;
         a = 10;
         */
        
        /*
         int *p;
         p = &a;
         */
        // 定义变量时的*仅仅是一个象征,没有其他特殊含义
        int *p = &a;
        
        // 不正确的写法
        // *p = &a;
        p = &a;
        
        // 这个时候的*的作用:访问指向变量p指向的存储空间
        *p = 20;
        
        char c = 'A';
        char *cp = &c;
        *cp = 'D';
        printf("%c\n", c);
    }
    

    03-指向指针的指针

    void pointer_to_pointer(void) {
        
        int a = 10;
        int *p = &a;
        int **pp = &p;
        
        // a = 20;
        // *p = 20;
        /*
         (*pp) == p
         *(*pp) == *p = a
         **pp == *p = a
         */
        **pp = 20;
        printf("%d\n", a);
        //int ***ppp = &pp;
        /*
         char a2 = 'A';
         char *p2 = &a2;
         */
    }
    

    04-指针

    void pointer_practice(void) {
        
        double d1 = 10.51;
        double d2 = 10.52;
        
        double *p;
        p = &d1;
        
        *p = 10.91;
        
        p = &d2;
        
        *p = 10.99;
        
        p = 0; // 清空指针
    //    p = NULL; // 清空指针
        
        // 清空指针后,不能再间接访问其它存储空间
    //    *p = 100.99; // Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
        
        printf("d1 = %f, d2 = %f\n", d1, d2);
    }
    

    05-指针的使用

    void user_pointer(void) {
        
        char a = 'A';
        char *c = &a;
        char **cc = &c;
        char ***ccc = &cc;
        
        a = 'G';
        
        printf("a = %c, %p\n", a, &a);
        printf("*c = %c, %p\n", *c, &c);
        printf("**cc = %c, %p\n", **cc, &cc);
        printf("***c = %c, %p\n", ***ccc, &ccc);
    }
    

    06-指针练习1

    void swap(int *v1, int *v2);
    void pointer_practice_1(void) {
        
        int a2 = 90;
        int b2 = 89;
        
        swap(&a2, &b2);
        printf("a2=%d, b2=%d\n", a2, b2);
    }
    
    /*
    // 交换的只是内部v1、v2的值
    void swap(int v1, int v2) {
        int temp = v1;
        v1 = v2;
        v2 = temp;
    }
    
    // 不能交换外面实参的值,仅仅是交换了内部指针的指向
    void swap(int *v1, int *v2) {
        int *temp;
        temp = v1;
        v1 = v2;
        v2 = temp;
    }
     */
    
    // 完成两个整型变量值的互换
    void swap(int *v1, int *v2) {
        int temp = *v1;
        *v1 = *v2;
        *v2 = temp;
    }
    

    07-指针练习2

    int sumAndMinus(int n1, int n2, int *n3);
    void pointer_practice_2(void) {
        
        int a = 10;
        int b = 7;
        
        // 存储和
        int he;
        // 存储差
        int cha;
        
        he = sumAndMinus(a, b, &cha);
        printf("和是:%d, 差是:%d\n", he, cha);
    }
    // 返回值是
    int sumAndMinus(int n1, int n2, int *n3) {
        
        *n3 = n1 - n2;
        return n1 + n2;
    }
    

    08-任何指针都占用8个字节的存储空间

    void any_pointer_takes_up_8_bytes_of_storage_space(void) {
        
        /*
         %d int
         %f float\double
         %ld long
         %lld long long
         %c char
         %s 字符串
         %zd  unsigned long
         */
        
        /*
         0000 0001
         0000 0010
         0000 0000
         0000 0000
         
         0000 0000 0000 0000 0000 0010 0000 0001
         */
        
        /*
         // 0000 0000 0000 0000 0000 0000 0000 0010
         int i = 2;
         // 0000 0001
         char ch = 1;
         
         char *p;
         p = &ch;
         
         // *p = 10;
         printf("ch的值是%d\n", *p);
        */
        
        char c = 'a'; // 1
        int a = 22; // 4
        long b = 2333232343545545455; // 8
        
        // 任何指针都占用8个字节的存储空间
        char *cp = &c;
        int *ap = &a;
        long *bp = &b;
        
        printf("cp = %zd, ap = %zd, bp = %zd\n", sizeof(cp), sizeof(ap), sizeof(bp));
        
        *cp = 'K';
        *ap = 999;
        *bp = 8888888888888888888;
        
        printf("c = %c, a = %d, b = %ld\n", c, a, b);
    }
    

    09-指针和数组

    void change_array(int array[]);
    void change_array2(int *array);
    void pointers_and_arrays(void) {
        
        /*
         1.数组元素的访问方式
         int ages[5];
         int *p;
         p = ages;
         1> 数组名[下标]  ages[i]
         2> 指针变量名[下标] p[i]
         3> *(p + i)
         
         2.指针变量+1,地址值究竟加多少,取决于指针的类型
         int *   4
         char *  1
         double * 8
         */
        
        /*
        // 20个字节
        int ages[5] = {10, 11, 19, 78, 67};
        change_array2(ages);
        */
        
        double d = 10.81;
        double *dp;
        dp = &d;
    
        printf("dp = %p\n", dp);
        printf("dp + 1 = %p\n", dp + 1);
    
        int ages[5] = {22,31,33,24,23};
    
        int *p;
        // 指针变量p指向了数组的首元素
        p = &ages[0];
        // 数组名就是数组的地址,也是数组首元素的地址
        //p = ages;
    
        *p = 99;
        p[2] = 100;
    
        /*
        p ---> &ages[0];
        p + 1 ---> &ages[1];
        p + 2 ---> &ages[2];
        p + i ---> &ages[i];
         */
    
        printf("*(p+3) = %d\n", *(p+3));
        printf("p[3] = %d\n", p[3]);
    
        for (int i = 0; i < 5; i++) {
            printf("ages[%d] = %d\n", i, *(p + i));
        }
    
        printf("p ---> %p\n", p);
        printf("p + 1 ---> %p\n", p + 1);
        printf("p + 2 ---> %p\n", p + 2);
    }
    
    /*
    void change_array(int array[]) {
        
        int s = sizeof(array);
        printf("%d\n", s);
    }
    
    // 利用一个指针来接收一个数组,指针变量array指向了数组的首元素
    void change_array2(int *array) {
        
        printf("%d\n", array[2]);
        printf("%d\n", *(array+2));
    }
     */
    

    10-数组元素的访问方式

    void accessed_array_elements(void) {
        
        // 1、数组元素的访问方式
        int ages[5] = {22, 31, 44, 56, 23};
        
        int *p;
        p = ages;
        
        for (int i = 0; i < 5; i++) {
            
            int a = ages[i]; // 1.数组名[下标] ages[i]
            int b = p[i]; // 2.指针变量名[下标] p[i]
            int c = *(p + i); // 3.*(p + i)
            
            printf("a[%d] = %d, b[%d] = %d, c[%d] = %d\n", i, a, i, b, i, c);
        }
        
        // 2、指针变量+1,地址究竟加多少,取决于指针的类型
    //    int *  4
    //    char *  1
    //    double *  8
    }
    

    11-指针和字符串

    void pointers_and_strings(void) {
        
        /*
         1.常量区
         存放一些常量字符串
         
         2.堆
         对象
         
         3.栈
         存放局部变量
         
         定义字符串的2种方式
         1> 利用数组
         char name[] = "zhang san";
         * 特点:字符串里面的字符是可以修改的
         * 使用场合:字符串的内容需要经常修改
         
         2> 利用指针
         char *name = "zhang san";
         * 特点:字符串其实是一个常量字符串,里面的字符是不能修改
         * 使用场合:字符串的内容不需要修改,而且这个字符串经常使用
         */
        
        /*
        char name[20];
        printf("请输入姓名:\n");
        scanf("%s", name);
        // 'j' 'a' 'c' 'k' '\0'
        // printf("%c\n", name[3]);
        // printf("刚才输入的字符串是:%s\n", name);
        */
        
        /*
        // 定义字符串数组
        char *name = "jack";
        //int ages[5];
        // 指针数组(字符串数组)
        char *names[5] = {"jack", "rose", "jake"};
        // 二维字符数组(字符串数组)
        char names2[2][10] = {"jack", "rose"};
        */
        
        // 定义字符串
        // 字符串变量
        char name[] = "hel";
        
        name[0] = 'T';
        
        printf("%s\n", name);
        printf("%lu\n", sizeof(name));
        
        // "hel" == 'h' + 'e' + 'l' + '\0'
        // 指针变量name2指向了字符串的首字符
        
        // 字符串常量
        char name_1[] = "ad_1";
        char name_2[] = "ad_1";
        
        printf("%p\n%p\n", name_1,name_2);
        printf("%s\n%s\n", name_1,name_2);
        
        char *name1 = "ad_2";
        char *name2 = "ad_2";
    //    *name1 = 'T'; // Thread 1: EXC_BAD_ACCESS (code=2, address=0x100000fae)
        
        printf("%p\n%p\n", name1,name2);
        printf("%s\n%s\n", name1,name2);
    }
    

    12-指针和字符串练习

    long string_length(char *s);
    void pointers_and_strings_practice(void) {
        
        /*
         (不包括\0)
         编写一个int string_len(char *s),返回字符串s的字符长度
         */
        long size = string_length("hello");
        printf("%ld\n", size);
    }
    

    13-字符串长度

    /*
    long string_length(char *s) {
        // 记录字符的个数
        int count = 0;
        
        // 如果指针当前指向的字符不是'\0'
        while ( *s != '\0') {
            // 个数+1
            count++;
            
            // 让指针指向下一个字符
            //s = s + 1;
            s++;
        }
        
        return count;
    }
        
    long string_length(char *s) {
        // 记录字符的个数
        int count = 0;
    
        // 如果指针当前指向的字符不是'\0'
        // 首先*s取出指向的字符
        // 然后s++
        while ( *s++ ) {
            // 个数+1
            count++;
    
            // 让指针指向下一个字符
            //s = s + 1;
            //s++;
        }
    
        return count;
    }
    */
    
    long string_length(char *s) {
    
        // 1.定义一个新的指针变量指向首字符
        char *p = s;
    
        /*
         while ( *s != '\0' )
         {
         s++;
         }*/
        while ( *s++ ) ;
        return s - p - 1;
    }
    

    14-判断某个字符串是否为回文

    // 回文就是从左边开始读 和 从右边开始读 都是一样的,比如"abcba"
    /*
     返回1代表是回文
     返回0代表不是回文
     */
    int determines_string_is_palindrome(char *str) {
        
        // 1.定义一个指向变量left指向字符串的首字符
        char *left = str;
        // 2.定义一个指向变量right指向字符串的末字符
        char *right = str + string_length(str) - 1;
        
        while (left < right) {
            
            // // 如果左边和右边的字符不一样
            if (*left++ != *right--) {
                return 0;
            }
        }
        return 1;
    }
    

    15-将两个字符串拼接在一起

    void string_link1(char s[], char t[]) {
        
        int i = 0;
        
        // 判断s[i]是否为字符串的尾部
        while (s[i] != '\0') {
            i++;
        }
        
        int j = 0;
        // 拷贝t的内容到s的后面
        while ((s[i] = t[j]) != '\0') {
            i++;
            j++;
        }
        
        /*
         更加精简的写法,仅作为参考(会有警告信息)
         void strlink2(char s[], char t[]) {
             int i = -1;
             
             // 判断s[i]是否为字符串的尾部
             while (s[++i]) ;
             
             int j = 0;
             // 拷贝t的内容到s的后面
             while (s[i++] = t[j++]) ;
         }
         */
    }
    

    16-将两个字符串拼接在一起

    void string_link2(char *s, char *t) {
        
        // 判断s[i]是否为字符串的尾部
        while (*s != '\0') {
            s++;
        }
        
        // 拷贝t的内容到s的后面
        while ((*s = *t) != '\0') {
            s++;
            t++;
        }
        
        /*
         更加精简的写法,仅作为参考(会有警告信息)
         void strlink2(char *s, char *t) {
             // 判断s[i]是否为字符串的尾部
             while (*s++);
             
             // 减回一次
             s--;
             
             // 拷贝t的内容到s的后面
             while ( *s++ = *t++ ) ;
         }
         */
    }
    

    17-返回指针的函数

    char *returns_function(void);
    void returns_pointer_function(void) {
        
        char *name = returns_function();
        printf("name = %s\n", name);
    }
    char *returns_function(void) {
        
        return "zhang san";
    }
    

    18-指向函数的指针

    double haha(double d, char *s, int a) {
        return 0;
    }
    void test() {
        printf("调用了test函数\n");
    }
    
    int pointer_sum(int a, int b) {
        return a + b;
    }
    void pointer_to_function(void) {
        
        /*
         1.看懂语法
         2.定义指向函数的指针
         double (*p)(double, char *, int);
         p = haha;
         或者
         double (*p)(double, char *, int) = haha;
         3.如何间接调用函数
         1> p(10.7, "jack", 10);
         2> (*p)(10.7, "jack", 10);
         */
        
        // 定义指针变量指向sum函数
        // 左边的int:指针变量p指向的函数返回int类型的数据
        // 右边的(int, int):指针变量p指向的函数有2个int类型的形参
        int (*p)(int, int);
        
        p = pointer_sum;
        
        //int c = p(10, 11);
        //int c = (*p)(10, 11);
        
        int c = pointer_sum(10, 9);
        printf("c is %d\n", c);
    }
    
    void test1() {
        
        // (*p)是固定写法,代表指针变量p将来肯定是指向函数
        // 左边的void:指针变量p指向的函数没有返回值
        // 右边的():指针变量p指向的函数没有形参
        void (*p)();
        
        // 指针变量p指向了test函数
        p = test;
        
        p();
        //(*p)(); // 利用指针变量间接调用函数
        
        //test(); // 直接调用函数
    }
    

    相关文章

      网友评论

        本文标题:11-指针

        本文链接:https://www.haomeiwen.com/subject/idsgahtx.html