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-指针

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

  • chapter 11-《pride and prejudice

    201706015-chapter 11-《pride and prejudice 傲慢与偏见》精读 Chapte...

  • 混淆知识点

    1、指针数组&数组指针、常量指针&指针常量、函数指针&指针函数 数组指针&指针数组 数组指针的定义 int (*p...

  • 李善友课程笔记11-孙正义如何利用时光机模型赢得科技浪潮

    李善友课程笔记11-孙正义如何利用时光机模型赢得科技浪潮

  • C语言

    C 指针、指针变量、函数指针、指针函数、指针数组、数组指针、C 数组

  • 指针

    普通指针指针的指针 数组指针 函数指针

  • 函数指针

    概念: 指针函数, 函数指针, 指针数组, 数组指针, 指向数组的指针, 指向函数指针数组的指针。

  • 结构体

    11-结构体 include include /*作业:1>实现mySt...

  • C:函数指针的坑

    关于该死的函数指针和指针函数 先来个目录 常量指针、指针常量 数组指针、指针数组 函数指针、指针函数 1、先看第一...

  • C 语言指针

    指针类型:指针的读取长度,指针的读取方向(大小端) 空指针,无类型指针,野指针 常量指针,指向常量的指针 http...

网友评论

    本文标题:11-指针

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