zoukankan      html  css  js  c++  java
  • 网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配

    2.1指针的使用

    2.2指针的计算

    2.3字符串操作

    2.4字符串函数的实现

    2.1指针的使用

    指针应用场景一

    交换两个变量的值

    1 void swap(int *pa, int *pb)
    2 {
    3     int t = *pa;
    4     *pa = *pb;
    5     *pb = t;
    6 }

    指针应用场景二a

    函数返回多个值,某些值就只能通过指针返回

    传入的参数实际上是需要保存带回的结果的变量

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 void minmax(int a[], int len, int *max, int *min);
     7 
     8 main()
     9 {
    10     int a[] = { 1,2,3,4,5,6,7,8,9,12,13,14,16,17,21,23,55, };
    11     int min, max;
    12 
    13     minmax(a, sizeof(a) / sizeof(a[0]), &max, &min);
    14 
    15     printf("min=%d,max=%d
    ", min, max);
    16 
    17     system("pause");
    18 }
    19 
    20 void minmax(int a[], int len, int *max, int *min)
    21 {
    22     int i;
    23     *min = *max = a[0];
    24 
    25     for (i = 1;i < len;i++)
    26     {
    27         if (a[i] < *min)
    28         {
    29             *min = a[i];
    30         }
    31         if (a[i] > *max)
    32         {
    33             *max = a[i];
    34         }
    35     }
    36 }

    指针应用场景二b

    函数返回运算的状态,结果通过指针返回

    常用的套路是让函数返回特殊的不属于有效范围内的值来表示出粗:

    -1或0(在文件操作会看到大量的例子)

    但是当任何数值都是有效的可能结果时,就得分开返回了

    状态用函数return返回,结果值通过指针参数返回。

    好处:容易把状态放到if语句

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 int divide(int a, int b, int *result);
     7 
     8 main()
     9 {
    10     int a = 5;
    11     int b = 2;
    12     int c;
    13 
    14     if (divide(a, b, &c))
    15     {
    16         printf("%d/%d=%d
    ", a, b, c);
    17     }
    18 
    19     system("pause");
    20 }
    21 
    22 int divide(int a, int b, int *result)
    23 {
    24     int ret = 1;
    25 
    26     if (b == 0)
    27     {
    28         ret = 0;
    29     }
    30     else
    31     {
    32         *result = a / b;
    33     }
    34     return ret;
    35 }

    指针最常见的错误

    定义了指针变量,还没有指向任何变量,就开始是使用指针

    p指向了一个未知地址,赋值可能会使得程序崩溃

    严重性 代码 说明 项目 文件 行 禁止显示状态
    错误 C4700 使用了未初始化的局部变量“p”

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 main()
     7 {
     8     int i = 6;
     9     int *p;
    10     int k;
    11     k = 12;
    12     *p = 12;
    13 
    14     system("pause");
    15 }

    数组参数

    以下四种函数原型是等价的:

    1 int sum(int *ar, int n);
    2 int sum(int *,int);
    3 int sum(int ar[], int n);
    4 int sum(int[], int);

    数组变量是特殊的指针

    数组变量本身表达地址,所以

    int a[10]; int *p=a;//无需用&取地址

    但是数组的单元表达的是变量,需要用&取地址

    a == &a[0];

    []运算符可以对数组做,也可以对指针做:

    p[0]<==>a[0]

    1     int min = 2;
    2 
    3     int *p = &min;
    4 
    5     printf("%d,%d
    ", *p, p[0]);

    *运算符可以对数组做,也可以对指针做:

    *a = 25;

    数组变量是const的指针,所以不能被赋值

    指针是const

    表示一旦得到了某个变量的地址,不能再指向其他变量

    严重性 代码 说明 项目 文件 行 禁止显示状态
    错误 C2166 左值指定 const 对象

    1     int i = 1;
    2     int * const q = &i;//q是const
    3 
    4     *q = 26;//OK
    5 
    6     q++;//ERROR

    所指是const

    表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)

    1     int i = 1;
    2     int j = 1;
    3 
    4     const int *p = &i;//ERROR (*p)是const
    5 
    6     i = 26;//OK
    7 
    8     p = &j;//OK

    判断哪个被const了的标志是const在*的左边还是右边

    1     int i = 1;
    2     
    3     const int *p1 = &i;
    4     int const *p2 = &i;
    5     int * const p3 = &i;

    转换

    总是可以把一个非const的值转换成const的

    比如:结构体

    1     int a = 15;
    2     f(&a);
    3     const int b = a;
    4 
    5     f(&b);//OK
    6 
    7     b = a + 1;//ERROR

    当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改

    const数组

    const int a[]={1,2,3,4,5,6,};

    数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int

    所以必须通过初始化进行赋值

    保护数组值

    因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值

    为了保护数组不被函数破坏,可以设置参数为const

    int sum(const int a[], int length);

    2.2指针的计算

    指针运算

    这些算术运算可以对指针做:
    给指针加、减一个整数(+, +=, -, -=)

    递增递减(++/--)

    两个指针相减

    1     int a[] = { 1,2,3,4,5,6,7,8 };
    2 
    3     int *p1 = &a[0];
    4     int *p2 = &a[4];
    5 
    6     printf("%d
    ", p2 - p1);//4

    *p++

    取出p所指的那个数据来,完事之后顺便把p移到下一个位置去

    *p的优先级虽然高,但是没有++高

    常用于数组类的连续空间操作

    在某些CPU上,这可以直接被翻译成一条汇编指令

    指针比较

    <, <=, ==, >, >=, !=都可以对指针做

    比较它们在内存中的地址

    数组中的单元的地址肯定是线性递增的

    0地址

    当然你的内存中有0地址,但是0地址通常是个不能随便碰的地址

    所以你的指针不应该具有0值

    因此可以用0地址来表示特殊的事情:

    返回的指针是无效的

    指针没有被真正初始化(先初始化为0)

    NULL是一个预定定义的符号,表示0地址

    有的编译器不愿意你用0来表示0地址

    指针的类型转换

    void *表示不知道指向什么东西的指针

    计算时与char *相同(但不相通)

    指针也可以转换类型

    int *p=&i;

    void *q=(void *)p;

    这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量

    用指针来做什么

    需要传入较大的数据时用作参数

    传入数组后对数组做操作

    函数返回不至一个结果

    需要用函数来修改不止一个变量

    动态申请的内存

    输入数据

    如果输入数据时,先告诉你个数,然后再输入,要记录每个数据

    C99可以用变量做数组定义的大小,C99之前呢?

    int *a=(int *)malloc(n*sizeof(int));

    malloc

    #include <stdlib.h>

    void * malloc(size_t size);

    向malloc申请的空间的大小是以字节为单位的

    返回的结果是void *,需要类型转换为自己需要的类型

    (int *)malloc(n*sizeof(int))

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 main()
     7 {
     8     int num;
     9     int *a;
    10     int i;
    11     scanf("%d", &num);
    12 
    13     a = (int *)malloc(num*sizeof(int));
    14 
    15     for (i = 0;i < num;i++)
    16     {
    17         scanf("%d", &a[i]);
    18     }
    19 
    20     for (i = num - 1;i >= 0;i--)
    21     {
    22         printf("%d ", a[i]);
    23     }
    24 
    25     free(a);
    26         
    27     system("pause");
    28 }

    没空间了?

    如果申请失败则返回0,或者叫做NULL

    free()

    把申请得来的空间还给“系统”

    申请过的空间,最终都应该要还

    只能还申请来的空间的首地址

    常见问题

    申请了没free->长时间运行内存逐渐下降

    新手:忘了

    老手:找不到合适的free的时间

    free过了再free

    地址变过了,直接去free

    办法:

    写了一个malloc,马上写上free

     1     int a[] = { 0 };
     2     int *p = a;
     3 
     4     if (p == a[0])//false
     5     {
     6         printf("true
    ");
     7     }
     8     else
     9     {
    10         printf("false
    ");
    11     }
    12 
    13     if (p == &a[0])//true
    14     {
    15         printf("true
    ");
    16     }
    17     else
    18     {
    19         printf("false
    ");
    20     }
    21 
    22     if (*p == a[0])//true
    23     {
    24         printf("true
    ");
    25     }
    26     else
    27     {
    28         printf("false
    ");
    29     }
    30         
    31     if (p[0] == a[0])//true
    32     {
    33         printf("true
    ");
    34     }
    35     else
    36     {
    37         printf("false
    ");
    38     }

    2.3字符串操作

    putchar

    int putchar(int c);

    向标准输出写一个字符

    返回写了几个字符,EOF(-1)表示写失败

    getchar

    int getchar(int c);

    向标准输入读入一个字符

    返回类型是int是为了返回EOF(-1)

    Windows->Ctrl-Z

    Unix->Ctrl-D

    字符串数组和字符型指针数组不一样

    char ch[3][5] <> char *pa[3]

    image

    程序参数

    int main(int argc, char const *argv[])

    argv[0]是命令本身

    当使用Unix的符号链接时,反映符号链接的名字

    2.4字符串函数的实现

    strlen

    size_t strlen(const char *s);

    返回s的字符串长度(不包括结尾的0)

    strcmp

    int strcmp(const char *s1, const char *s2);

    比较两个字符串,返回:

    0: s1==s2

    1: s1>s2

    -1: s1<s2

    strcpy

    char *strcpy(char *restrict dst, const char *restrict src);

    把str的字符串拷贝到dst

    restrict表明stc和dst不重叠(C99)

    返回dst

    为了能链起代码来

    字符串中找字符

    char *strchr(const char *s, int c);

    char *strrchr(const char *s, int c);

    返回NULL表示没有找到

    字符串中找字符串

    char *strstr(const char *s1, const char *s2);

    char *strcasestr(const char *s1, const char *s2);

  • 相关阅读:
    mint17上建立lamp环境
    iptables开始ftp
    查看mysql集群状态是否正常
    限制SSH访问源,禁止4A之外的地址跳转访问
    查看cpu、内存和硬盘
    降kipmi0的CPU
    更改密钥对
    eNSP
    划分分区GPT11
    修改虚机IP
  • 原文地址:https://www.cnblogs.com/denggelin/p/5579079.html
Copyright © 2011-2022 走看看