zoukankan      html  css  js  c++  java
  • c语言基础学习07_指针

    =============================================================================

    涉及到的知识点有:

    1、指针、指针的概念、指针变量的定义、取地址运算符 &、无类型指针、
    指针占用内存的说明、野指针 与 空指针、空指针理解的扩展、指针的兼容性(即指针类型之间一定要匹配)、
    不同的数据类型在内存中占用的地址、指向常量的指针 和 指针常量、指针与数组的关系、指针运算、
    通过指针使用数组元素、不同类型的指针的区别以及与数组的关系、小案例:int类型与ip地址的对应关系
    使用指针给二维数组排序、

    2、指针数组、二级指针(指向指针的指针)、三级指针及其以上指针、函数的参数为指针变量时(指针变量作为函数的参数)、
    函数的参数为数组名时(即数组名作为函数的参数)、函数的返回值为指针时(即指针作为函数的返回值)、
    几个c语言的库函数:memset、memcpy、memmove函数,使用的时候需要包含头文件 #include <string.h>、

    3、字符指针 与 字符串、通过指针访问字符串数组、通过指针使得字符串逆置、函数的参数为char *(即char *作为函数的参数)、
    自定义函数实现求字符串长度和字符串拷贝、例外:如果函数的参数是一个字符串时,那么并不需要再传递一个参数说明这个字符串有多长、

    4、指针数组作为main函数的形参、举个小例子:用到main函数的参数,实现计算两个数的和、
    课后作业写一个程序,需要用到main函数的参数、

    =============================================================================
    c语言是面向过程的语言,是弱类型语言,c语言的源代码基本就是无数个函数的堆砌。
    即很多函数就组成c语言源代码了,也即它的源代码基本就是函数构成的。

    C语言里面的test()和test(void)是不一样的。什么也不写的话,C语言就比较含糊了,容易出错,结果不可知。
    C++语言里面的test()和test(void)是一样的。

    c语言几个松散的地方(不足的地方,不严禁的地方,它容易出错的地方)。

    课后思考:
    写一个函数求字符串的长度。课后思考,用递归函数实现求字符串长度。

    =============================================================================
    指针

    指针是c语言里面最抽象的、最重要的、最常用的。

    指针的概念:

    指针变量也是一个变量,
    指针存放的内容是一个地址,该地址指向一块内存空间,
    指针是一种数据类型(指针类型)。
    --------------------------------------
    计算机内存的最小单位是什么?BYTE(字节)

    对于内存,每个BYTE(字节)都有一个唯一不同的编号,这个编号就是内存地址。

    操作系统就给内存的每一个字节编了一个号,所以说:一个编号对应的是一个BYTE(字节)的空间大小。

    打比方:
    1    ->    BYTE
    2    ->    BYTE
    3    ->    BYTE
    4    ->    BYTE
        对应于
    --------------------------------------
    一个int多大?答:4个BYTE(字节),所以一个int占用了了4个编号(即4个不同的内存地址)。

    地址的编号:在32位系统下是一个4个字节的无符号整数;在64位系统下是一个8个字节的无符号整数。
    (因为地址不可能是负的,又因为无符号数可以表达一个更大的地址,有符号数表示的最大地址会变小)
    -----------------------------------------------------------------------------
    指针变量的定义:

    可以定义一个指向一个变量的指针变量。
    -----------------------------------------------------------------------------
    取地址运算符 &

    & 可以取得一个变量在内存当中的地址。(取地址取的是内存地址)

    register int a; //寄存器变量,这种变量不在内存里面,而在cpu里面,所以是没有地址的,
    所以寄存器变量不能使用&来得到地址。
    -----------------------------------------------------------------------------
    无类型指针

    定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将 void * 转化为其他类型指针,
    也可以用 (void *) 将其他类型强制转化为void类型指针。

    void *p; 指针之间赋值需要类型相同,但任何类型的指针都可以赋值给 void * 。
    -----------------------------------------------------------------------------

     1 linux下示例代码如下:
     2 
     3 int main()
     4 {
     5     int *p; //定义了一个可以指向int类型地址的指针变量,指针变量的名字叫p。*不是指针变量名字的一部分。
     6             //int * 是一种数据类型。
     7     int a;  //定义了一个int类型的变量,int变量的名字叫a。
     8 
     9     a = 1;  //int * 和 int是两种不同的数据类型。
    10     p = &a; //把a的内存地址赋值给指针变量p。
    11 
    12     printf("%p
    ", p);  //0x7fff5b2faedc 输出的是a的首地址的编号,不会把四个编号都输出的。
    13                         //而且注意:每一次执行该代码后,输出的编号都会发生变化!
    14 
    15     *p = 10;    //通过指针变量间接的访问a的值,*p代表指针指向变量的值,p代表指向变量的地址。
    16     printf("a = %d
    ", a);  //a = 10; 通过上面的方法把a的值改变了。
    17 
    18     a = 100;
    19     printf("%d
    ", *p); //100   通过指针变量间接的访问a的值。
    20 
    21     int b = 2;
    22     p = &b; //又把b的内存地址赋值给p。
    23     *p = 20;
    24     printf("b = %d
    ", b);  //20
    25 
    26     //char *p1 = &a;  //相当于 char *p1; p1 = &a;//两个类型不相同的地址。即指针类型不兼容。那么我们强转试试!
    27     char *p1 = (char *)&a;
    28     a = 123456;
    29     *p1 = 0;
    30     printf("a = %d
    ", a);  //a = 123392  就算强转后也会出现问题,所以要避免指针类型不兼容问题。
    31 
    32     void *p2;   //可以指向任何类型的地址,void代表无类型。
    33 
    34     return 0;
    35 }

    -----------------------------------------------------------------------------

    指针占用内存的说明

    在同一个系统下,不管指针指向什么样类型的变量,地址的大小(或叫编号的大小)总是一样的。

     1 linux下示例代码如下:
     2 
     3 int main()
     4 {
     5     char *p1;
     6     int *p2;
     7     long long *p3;
     8 
     9     printf("%lu, %lu, %lu
    ", sizeof(p1), sizeof(p2), sizeof(p3));  //实质是:编号的大小是多少?
    10     return 0;   //输出的是 8, 8, 8
    11                 //地址的编号:在32位系统下是一个4个字节的无符号整数;在64位系统下是一个8个字节的无符号整数。
    12                 //指针变量的名字叫p1、p2、p3。指针变量的大小是多大呢?因为指针变量对应的是某某的首地址的编号,
    13                 //即指针变量对应的是编号,而编号就是内存地址。即编号在64位系统下是一个8个字节的无符号整数。
    14                 //所以指针变量的大小就是编号的大小,而编号在64位系统下用8个字节的无符号整数表示。
    15                 //举例子说明下:同一个酒店,房间的编号的长度都是一样的。
    16 
    17 }

    --------------------------------------
    再比如:

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int *p1;
     8     int a = 0;
     9     p1 = &a; 
    10     *p1 = 10; 
    11     //p1 = 10;
    12 
    13     int *p2;
    14     p2 = &a; 
    15     //*p2是什么?不管是*p1还是*p2都代表变量a的值,但p1和p2确实是两个不同的指针变量。
    16     return 0;
    17 }

    画图说明如下:

    =============================================================================
    野指针 与 空指针

    野指针:没有指向任何有效地址的指针变量,所以在代码中避免出现野指针,
    如果一个指针不能确定指向任何一个变量地址,那么就将这个指针变成空指针。

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int *p; 
     8     *p = 100;   //不能这样写,没有初始化过值的指针,这种指针叫野指针。
     9     return 0;   //因为地址编号所占用的内存不是你程序要调用的内存。对于操作系统而言,不是你的内存你就不能改!
    10                 //如果你非要改的话,操作系统就会发现你在做非法操作,会直接把你清理出去了。即程序出错。
    11 }

    编译上段程序没有错误,运行上段程序会出现一个错误:Segmentation fault(段错误,也即分段故障)
    -----------------------------------------------------------------------------
    空指针:就是指向了NULL的指针变量。

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int *p;     //两句代码相当于一句:int *p = NULL;
     8     p = NULL;   //如果一个指针变量没有明确的指向一块内存,那么就把这个指针变量指向NULL。
     9                 //这个指针就是空指针,空指针是合法的。
    10                 //实际上NULL并不是c语言的关键字,NULL在c语言中的定义是:#define NULL 0
    11                 //NULL在c语言里面就是一个宏常量,值是0。那么我们为什么不直接写0呢?
    12                 //NULL代表的是空指针,而不是一个整数零,这样看的会舒服些。(这只是粗浅易懂的解释)
    13     return 0;
    14 }

    程序中不要出现野指针,但可以出现空指针。
    --------------------------------------
    空指针理解的扩展:

    1 注意:
    2 int a = 0;
    3 int *p = &a;    //相当于 int *p; p = &a;
    4 
    5 int *node = NULL;    //相当于:int *node; node = NULL;

    NULL就是系统定义特殊的0,把你初始化的指针指向它,可以防止“野指针”的恶果。

    NULL是个好东西,给一出生的指针一个安分的家。
    --------------------------------------
    用C语言编程不能不说指针,说道指针又不能不提NULL,那么NULL究竟是个什么东西呢? C语言中又定义,定义如下:

    1 #undef NULL
    2 #if defined(__cplusplus)
    3 #define NULL 0
    4 #else
    5 #define NULL ((void *)0)
    6 #endif

    所以我觉得,如果一个指针被赋予NULL,应该就相当于这个指针执行了0x0000这个逻辑地址,
    但是C语言中0x0000这个逻辑地址用户是不能使用的,
    (有些人说是因为0x0000没有映射到物理地址,也有人说是因为0x0000映射到的地址是操作系统用于判断野指针的,我也不太懂,总之就是用户不能使用啦)
    所以当你试图取一个指向了NULL的指针的内容(或者叫值)时,就会提示段错误,听着有点绕,看程序:

    1 int *node = NULL;
    2 int a = 0;
    3 a = *node;    //*node的意思是:取指针变量node的值。然后赋值给a。
    4     
    5 printf("%d
    ", a);

    *node的意思是:取指针变量node的值,也就是逻辑地址0x0000,而这个地址是不能被访问的(即不能被取出来的),
    c语言语法上没有问题,所以编译器编译没有问题,但是编译器编译后运行会出现段错误。

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int *p = NULL;    //相当于 int *p = 0; 但一般不这么写啊!
     8     int a = 0;
     9     a = *p; 
    10     printf("%d
    ", a); 
    11 
    12     return 0;
    13 }
    14 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p6 p6.c
    15 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p6
    16 Segmentation fault(段错误,也即分段故障)
    17 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# 

    =============================================================================
    指针的兼容性(即指针类型之间一定要匹配)

    指针之间赋值比普通数据类型赋值检查更为严格,例如:不可以把一个 double * 赋值给int。

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int *p; 
     6     char b = 1;
     7     p = &b;     //指针类型之间一定要匹配,不然会有警告,强行运行的话,结果不可控!
     8 
     9     return 0;
    10 }

    警告如下:
    warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
    警告:不兼容的指针类型分配[-Wincompatible-pointer-types]

    =============================================================================

    我们不要把指针想象的特别神秘!其实指针变量也是一个变量。
    它里面放的就是一个地址的编号,地址的编号就是一个8个字节的无符号的整数(64位系统下)。
    区别是:这个整数不能直接赋值,而是来自于对另外一个变量的取地址操作而得到!

    =============================================================================
    不同的数据类型在内存中占用的地址

    我们先看几个现象:

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     char a[10];
     8     printf("%p, %p, %p, %p
    ", a, &a[0], &a[1], &a[2]);
     9     return 0;
    10 }
    11 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    12 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    13 0x7ffe4f449e90, 0x7ffe4f449e90, 0x7ffe4f449e91, 0x7ffe4f449e92
    14 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    15 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    16 0x7ffdae4e3c20, 0x7ffdae4e3c20, 0x7ffdae4e3c21, 0x7ffdae4e3c22
    17 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    18 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    19 0x7ffd37b6f530, 0x7ffd37b6f530, 0x7ffd37b6f531, 0x7ffd37b6f532
    20 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针#

    每一次编译后执行,输出的地址会发生变化,但是相邻地址间的间隔不变。
    --------------------------------------
    再比如:

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int a[10];
     8     printf("%p, %p, %p, %p
    ", a, &a[0], &a[1], &a[2]);
     9     return 0;
    10 }
    11 
    12 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    13 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    14 0x7ffe9e845ec0, 0x7ffe9e845ec0, 0x7ffe9e845ec4, 0x7ffe9e845ec8
    15 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    16 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    17 0x7ffed37c6bc0, 0x7ffed37c6bc0, 0x7ffed37c6bc4, 0x7ffed37c6bc8
    18 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p8 p8.c
    19 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p8
    20 0x7ffdb8b422c0, 0x7ffdb8b422c0, 0x7ffdb8b422c4, 0x7ffdb8b422c8
    21 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# 

    每一次编译后执行,输出的地址会发生变化,但是相邻地址间的间隔不变。

    其余的类型就不一一举例啦!

    =============================================================================
    指向常量的指针 和 指针常量

    const int *p;  //定义一个指向常量的指针。

    int *const p;  //定义一个指针常量,一旦指向某一变量的地址后,不可再指向其他变量的地址。(注意:指针常量也叫常量指针

    二者区别:
    const int *p; //p是一个变量,但指向一个常量。(即p可以指向任何地址,但是只能通过*p来读这块地址的内容,不能通过*p来写这块地址的内容)

    int *const p; //p是一个常量,但指向一个变量或者常量。(即如果一旦p指向了任何一个有效的地址后,就不可再指向其他变量的地址,但可以通过*p来读写这块地址的内容)

    --------------------------------------

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main01()
     6 {
     7     int a = 0;
     8     int *p = &a;        //此时的p指向了一个int类型的地址,可以通过*p的方式来修改这个内存a的值。
     9     *p = 10;
    10     printf("a = %d
    ", *p); //或者printf("a = %d
    ", a);    //此时的*p可读可写。
    11 
    12     return 0;
    13 }
    14 
    15 int main()
    16 {
    17     int a = 0;
    18     const int *p = &a;  //此时的p指向了一个int类型的地址,但不可以通过*p的方式来修改这个内存a的值。
    19     //*p = 10;
    20     a = 10;             //但是呢,不可以通过*p来改a的值,可以通过a去修改a的值。
    21     printf("a = %d
    ", *p); //或者printf("a = %d
    ", a);    //此时的*p可读不可写。
    22 
    23     //c语言的一个小漏洞
    24     const int b = 100;
    25     //b = 0;    //定义了一个常量,那么这个常量权限是只读了。
    26 
    27     //通过指针的方法:即可以通过指向一个变量地址的指针去指向它,然后通过*p1去间接的修改b的值。
    28     //注意编译的时候会出现警告!我们忽略这个警告强行改!这时把b的值改了!!!
    29     //warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    30     //警告:赋值时从指针目标类型丢弃“const”限定符[-Wdiscarded-qualifiers]
    31      
    32     //这就是在c语言中用常量的时候不用const了!
    33     //因为c语言中的const是有问题的,因为可以通过指针变量间接的修改const定义的常量的值,所以在c语言中用#define定义常量的时候更多。
    34       
    35     //为什么#define不能改呢?实质上#define就是一个文本替换,直接把它替换成一个整数了,整数又不是一个变量。
    36     //但是在C++中就没有这个漏洞了。为什么呢?因为c++里面的const是个真的const,而c语言中的const只是在语法的角度不让你去赋值,实际上是假的。
    37     //这是c语言本身存在的弱项。
    38 
    39     int *p1;    
    40     p1 = &b;    //为了避免这个warning,使用强转即可:p1 = (int *)&b;
    41     *p1 = 0;
    42     printf("b = %d
    ", b);  //或者printf("b = %d
    ", *p);
    43 
    44     int *const p2 = &a;    //表示p2指向了a的地址,而且p2只能指向a的地址,不可再指向其他变量的地址。
    45     //p2 = &b;//直接编译错误//p2是一个指针常量,p2只能指向固定的一个变量的地址,但可以用*p2读写这个变量的值。
    46 
    47     return 0;
    48 }

    =============================================================================
    指针与数组的关系

     1 linux下示例代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  //数组的名字a就是数组首元素的地址。
     8     int *p; 
     9     p = a;      //当指针变量指向一个数组的时候,c语言规定指针变量名可以当做数组名使用。
    10     //p = a[0]; //二者等价
    11 
    12     a[2] = 200;
    13     p[3] = 100; //相当于a[3] = 100;但二者之间也有区别哦!区别如下:
    14     printf("%lu, %lu
    ", sizeof(a), sizeof(p));//40, 8  二者所占内存大小不一样。
    15 
    16     int i;
    17     for (i = 0; i <10; i++)
    18     {   
    19         //printf("a[%d] = %d
    ", i, a[i]);  //输出没有问题
    20         printf("a[%d] = %d
    ", i, p[i]);  //输出也没有问题,完全把指针当数组用!
    21     }   
    22 
    23     return 0;
    24 }

    --------------------------------------
    一级指针画图小说明如下:

    =============================================================================
    指针运算

    指针变量可以进行计算,如果是 int * 类型每加一,变化4个整数;
    如果是 char * 类型每加一,变化1个整数。其他类型以此类推。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a = 0;
     6     int *p = &a; 
     7     printf("%p, %p, %p
    ", p, p + 1, p + 2 );   //0x7fff5c2a518c, 0x7fff5c2a5190, 0x7fff5c2a5194
     8 
     9     return 0;
    10 }

    -----------------------------------------------------------------------------
    指针运算小例子:

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a[10] = { 0 };
     6     int *p = a;
     7 
     8     p += 5;
     9     *p = 1;
    10 
    11     p -=2;
    12     *p = 3;
    13 
    14     int i;
    15     for (i = 0; i < 10; i++)
    16     {   
    17         printf("a[%d] = %d
    ", i, a[i]);
    18     }   
    19 
    20     return 0;
    21 }
    22 输出的是:
    23 a[0] = 0
    24 a[1] = 0
    25 a[2] = 0
    26 a[3] = 3
    27 a[4] = 0
    28 a[5] = 1
    29 a[6] = 0
    30 a[7] = 0
    31 a[8] = 0
    32 a[9] = 0

    -----------------------------------------------------------------------------
    通过指针使用数组元素

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     6     int *p = a; //指针p指向a的首地址。
     7     p[3] = 100; //等价于 *(p + 3) = 100; 一般写成左边那样。
     8 
     9         printf("a[%d] = %d
    ", i, a[i]);
    10     int i;
    11     for (i = 0; i < 10; i++)
    12     {   
    13     }   
    14 
    15     return 0;
    16 }

    =============================================================================
    不同类型的指针的区别以及与数组的关系

    极端例子如下:
    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a = 0x12345678;
     6     char *p = (char *)&a;
     7     printf("%x, %x, %x, %x, %x
    ", *p, p[0], p[1], p[2], p[3]); //%x的意思是按照十六进制的有符号整数输出(小写) 
     8     printf("--------------------
    ");
     9 
    10     *p = 0;
    11     p[3] = 0;
    12     printf("%08x
    ", a); 
    13     printf("--------------------
    ");
    14 
    15     char b[20] = { 0 };
    16     int *p1 = (int *)&b;
    17     p1[3] = 0x12345678;
    18 
    19     int i;
    20     for (i = 0; i < 20; i++)
    21     {   
    22         printf("b[%d] = %x
    ", i, b[i]);
    23     }   
    24     printf("--------------------
    ");
    25 
    26     return 0;
    27 }
    28 
    29 输出的结果是:
    30 78, 78, 56, 34, 12
    31 --------------------
    32 00345600
    33 --------------------
    34 b[0] = 0
    35 b[1] = 0
    36 b[2] = 0
    37 b[3] = 0
    38 b[4] = 0
    39 b[5] = 0
    40 b[6] = 0
    41 b[7] = 0
    42 b[8] = 0
    43 b[9] = 0
    44 b[10] = 0
    45 b[11] = 0
    46 b[12] = 78
    47 b[13] = 56
    48 b[14] = 34
    49 b[15] = 12
    50 b[16] = 0
    51 b[17] = 0
    52 b[18] = 0
    53 b[19] = 0

    --------------------
    说明:小端对齐输出。

    小结:c语言中所有的数据类型都可以理解为一个char的数组。

    -----------------------------------------------------------------------------
    小案例:int类型与ip地址的对应关系。

    实际上的ip地址是一个无符号的整数构成的。1个int,4个字节。

    1、把整数转换为ip地址

    ip地址的格式:
    0.0.0.0 ~ 255.255.255.255

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     unsigned int a = 235423523; //0x 0e 08 47 23  (14.8.71.35)  0e的0可以省略哦!
     6     scanf("%u", &a);
     7     unsigned char *p = (unsigned char*)&a;
     8     printf("%u.%u.%u.%u
    ", p[3], p[2], p[1], p[0]);
     9     printf("---------------------
    ");
    10 
    11     int i;
    12     for (i = 0; i < 4; i++)
    13     {   
    14         printf("%2x,%2u
    ", p[i], p[i]);
    15     }   
    16 
    17     return 0;
    18 }
    19 输出结果是:
    20 
    21 56596596529659
    22 108.8.25.251
    23 ---------------------
    24 fb,251
    25 1925
    26  88
    27 6c,108

    -----------------------------------------------------------------------------
    2、把ip地址转换为整数

    输入一个ip地址
    char a[100] = "192.168.2.5"
    把这个ip转化为unsigned int类型的整数。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     char a[] = "192.168.2.5";
     6     unsigned int ip = 0;
     7     unsigned char *p = (unsigned char *)&ip;
     8     int a1, a2, a3, a4; 
     9 
    10     sscanf(a, "%d.%d.%d.%d
    ", &a1, &a2, &a3, &a4);    //sscanf从某一个格式化字符串中读取到我们想要的东西,找到后通过转义的方式取出来.
    11     //printf("%d.%d.%d.%d
    ", a1, a2, a3, a4);
    12     
    13     p[0] = a4;//*p = a4; 二者等价
    14     p[1] = a3; 
    15     p[2] = a2; 
    16     p[3] = a1; 
    17    
    18     /*  
    19     *p = a4;
    20     p++;
    21     *p = a3;
    22     p++;
    23     *p = a2;
    24     p++;
    25     *p = a1;
    26     */
    27 
    28     printf("%u
    ", ip);
    29 
    30     return 0;
    31 
    32 }
    33 输出结果是:
    34 
    35 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o p16 p16.c
    36 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# p16
    37 3232236037
    38 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# ping 3232236037
    39 PING 3232236037 (192.168.2.5) 56(84) bytes of data.

    -----------------------------------------------------------------------------
    3、使用指针给二维数组排序

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     char a[2][5] = { { 4, 3, 5, 9, 78 }, { 52, 21, 5, 6, 4 } };
     6     char *p = (char *)a;
     7 
     8     int i, j;
     9     for (i = 0; i < 10; i++)
    10     {   
    11         for (j =1; j < 10 - i; j++)
    12         {   
    13             if (p[j] < p[j - 1]) 
    14             {   
    15                 char tmp = p[j];
    16                 p[j] = p[j - 1]; 
    17                 p[j - 1] = tmp;
    18 
    19             }   
    20         }   
    21     }   
    22 
    23     for (i = 0; i < 2; i++)
    24     {   
    25         for (j = 0; j < 5; j++)
    26         {   
    27             printf("%d
    ", a[i][j]);
    28         }   
    29     }   
    30 
    31     return 0;
    32 
    33 }
    34 
    35 输出的结果是:
    36 3
    37 4
    38 4
    39 5
    40 5
    41 6
    42 9
    43 21
    44 52
    45 78

    =============================================================================
    指针数组

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     char *a[10];    //定义了一个指针数组,指针数组的名字叫a,每个成员是char *类型,一共10个成员。
     6     int *b[10];     //定义了一个指针数组,指针数组的名字叫b,每个成员是char *类型,一共10个成员。
     7 
     8     printf("%lu, %lu
    ", sizeof(a), sizeof(b)); //80, 80
     9 
    10     int i = 0;
    11     //a = &i;       //指针数组名不能做左值。
    12     //b = &i;       //指针数组名不能做左值。
    13 
    14     b[0] = &i;      //b[0]的类型是int *。
    15     printf("%lu, %lu
    ", sizeof(b[0]), sizeof(*b[0]));  //8, 4  *b[0]是一个数组的成员。
    16 
    17     return 0;
    18 
    19 }

    -----------------------------------------------------------------------------
    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int *a[10] = { NULL };  //定义了一个指针数组,指针数组的名字叫a,每个成员是int *类型的,一共有10个成员。
     6     int b, c, d;            //对于指针数组来说,要先有指针的性质,再有数组的性质,即先得获得地址,然后对数组进行操作。
     7 
     8     a[0] = &b;      //a是指针数组的名字。
     9     a[1] = &c;      //a[0]是指针变量,
    10     a[2] = &d; 
    11 
    12     *a[0] = 10;     //*a[0]是一个数组的成员之一。
    13 
    14     printf("%d
    ", b); 
    15 
    16     return 0;
    17 }

    =============================================================================
    二级指针(指向指针的指针)

    指针是一个变量,既然是变量就也存在内存地址,所以可以定义一个指向指针的指针。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a = 0;
     6     int *p = &a; 
     7     int **pp = &p;  //二级指针:指向指针的指针。
     8     pp = &p;        //pp代表一级指针内存地址的编号。
     9     
    10     //*pp = 1000;   //等号左端是指针类型的变量,等号右边是int类型。
    11                     //或者可以这么理解,指针变量指的是一个地址,无法对它进行赋值。
    12                     //再或者说,我们两对应的内存地方不一样。操作系统不让你干这非法的事情。(分段错误)
    13 
    14     **pp = 10; 
    15     printf("%d
    ",a );  //10
    16 
    17     return 0;
    18 }

    二级指针说明图如下:

    =============================================================================
    三级指针及其以上指针

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a = 0;//零级“指针”,a有内存地址编号,a的内容(值)为0。
     6     int *p = &a;//一级指针,p代表a的内存地址编号;*p代表a的内容(值)。
     7     int **pp = &p;//二级指针,pp代表p的内存地址编号;*pp代表a的内存地址编号;**pp代表a的内容(值)。
     8     int ***ppp = &pp;//三级指针,ppp代表pp的内存地址编号;*ppp代表p的内存地址编号;**ppp代表a的内存地址编号,***ppp代表a的内容(值)。
     9     int ****pppp = &ppp;//四级指针
    10 
    11     ****pppp = 100;
    12     printf("a = %d
    ", a); //100
    13 
    14     return 0;
    15 }
    16 pppp代表ppp的内存地址编号;
    17 *pppp代表pp的内存地址编号;
    18 **pppp代表p的内存地址编号;
    19 ***pppp代表a的内存地址编号;
    20 ****pppp代表a的内容(值)。

    linux下示例代码如下图所示:

    特别注意:
    能用一级指针解决的问题不要用二级指针,能用二级指针解决的不用三级指针,指针级数过多会导致程序很复杂。
    工作中大量使用的是一级指针,二级指针也很常用,三级指针就很罕见了,四级指针几乎没有。但笔试会考你哦!可以画图解决!

    =============================================================================

    函数的参数为指针变量(指针变量作为函数的参数)

    实际上指针更多的时候用在函数的参数上。

    函数的参数可以使是指针类型。它的作用是将一个变量的地址编号传送给另一个函数。

    void test(int *p); //定义一个函数,形参是int *类型。

    c语言中如果想通过在一个函数的内部修改外部实参的值,那么就需要给函数的参数传递这个实参的地址。
    -----------------------------------------------------------------------------
    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 void swap(int a, int b) //swap是交换的意思。
     4 {
     5     int tmp = a;
     6     a = b;
     7     b = tmp;
     8     printf("a = %d, b = %d
    ", a, b);//a = 2, b = 1  形参中的值发生变化了。
     9 }
    10 
    11 int main()
    12 {
    13     int a = 1;
    14     int b = 2;
    15 
    16     swap(a, b); 
    17     printf("a = %d, b = %d
    ", a, b);//a = 1, b = 2  c语言中实参的值会传给形参,而形参值的改变并不会影响到实参。
    18     return 0;
    19 }
    20 -----------------------------------------------------------------------------
    21 那么现在我就想在一个函数的内部修改外部实参的值,那么就需要给函数的参数传递这个实参的地址。代码如下:
    22 
    23 #include <stdio.h>
    24 
    25 void swap(int *a, int *b) 
    26 {
    27     int tmp = *a;
    28     *a = *b;
    29     *b = tmp;
    30     printf("a = %d, b = %d
    ", a, b);//a = 2, b = 1  形参中的值发生变化了。
    31 }
    32 
    33 int main()
    34 {
    35     int a = 1;
    36     int b = 2;
    37 
    38     swap(&a, &b); //那么现在我就想在一个函数的内部修改外部实参的值,那么就需要给函数的参数传递这个实参的地址。
    39     printf("a = %d, b = %d
    ", a, b);//a = 2, b = 1  实参中的值发生变化了。
    40     return 0;
    41 }

    函数参数是指针变量的画图说明如下:

    即:c语言想通过函数内部来修改实参的值,只能给函数传递实参的地址来间接的修改实参的值。
    例如scanf函数:
    int a;
    scanf("%d", &a);//scanf是一个函数,现在要通过函数内部来修改实参a的值,只能用传递a的地址的方式修改a的值
    =============================================================================

    函数的参数为数组名时(即数组名作为函数的参数)

    当一个数组名作为函数的形参的时候,c语言将数组名解释为指针变量,其实是一个指针变量名。

    如果数组名作为函数的参数,那么这个就不是数组名了,而是一个指针变量名。

    当把一个数组名作为函数的参数时,修改形参的值的时候,同时也影响实参的数组成员的值。

    如果把一个数组名作为函数的参数,那么在函数内部就不知道这个数组的元素个数了,需要再增加一个参数来标明这个数组的大小。

    如果将一个数组作为函数的形参进行传递,那么数组的内容可以在被调用函数的内部进行修改,
    有时候不希望这样的事情发生,所以要对形参采用const进行修饰。

    -----------------------------------------------------------------------------
    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 //此三种写法均可:常写的是void test(int *a)这一种!
     4 //void test(int a[10])
     5 //void test(int a[])
     6 /*
     7 void test(int *a)
     8 {
     9     printf("%lu
    ", sizeof(a));
    10     a[50] = 50;
    11 }
    12 */
    13 
    14 /*
    15 //为了从语法的角度不让在函数的内部修改数组成员的值,用const进行限定,如下:
    16 void test(const int *a)
    17 {
    18     printf("%lu
    ", sizeof(a));
    19     //a[5] = 100;   该句编译通不过,出现错误。因为此时的数组只能读,不能改。
    20 }
    21 */
    22 
    23 //现在我非要在加有const的函数内部进行修改呢?可以,使用指针就可以绕过c语言的语法!
    24 void test(const int *a) 
    25 {
    26     printf("%lu
    ", sizeof(a));
    27 
    28     int *p = (int *)a;
    29     p[5] = 50;  //此时可以修改了!
    30 }
    31 
    32 int main()
    33 {
    34     int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    35     printf("%lu
    ", sizeof(a));
    36     printf("----------------------
    ");
    37 
    38     test(a);
    39 
    40     int i;
    41     for (i = 0; i < 10; i++)
    42     {   
    43         printf("a[%d] = %d
    ", i, a[i]);
    44     }   
    45 
    46     return 0;
    47 }

    =============================================================================
    函数的返回值为指针时(即指针作为函数的返回值)

    1 int *test()    //函数的返回值类型是指针类型(具体的讲解在下一节:内存管理)
    2 {
    3     return NULL;    
    4 }

    =============================================================================
    几个c语言的库函数:memset、memcpy、memmove函数,使用的时候需要包含头文件 #include <string.h>

    这三个函数分别实现内存设置、内存复制、内存移动功能。

    --------------------------------------
    memset的功能是:将指定区域的内存置空(设置为0)。
    void *memset(void *s, int c, size_t n);
    第一个参数是:指定要置空的内存的首地址;
    第二个参数是:要设置的值,一般写0;
    第三个参数是:这块内存的大小,单位:字节。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main()
     5 {
     6     int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     7     //想把一个已经初始化的数组成员的值都变成0。
     8     
     9     //法一:传统的方法如下:
    10     //a[10] = { 0 };//不能这样来啊,这叫定义后立马进行初始化。
    11     /*  
    12     int i;
    13     for (i = 0; i < 10; i++)
    14     {
    15         a[i] = 0;
    16     }
    17     */
    18 
    19     //法二:使用c语言库函数memset。
    20     memset(a, 0, sizeof(a));
    21 
    22     int i;
    23     for (i = 0; i < 10; i++)
    24     {   
    25         printf("a[%d] = %d
    ", i, a[i]);
    26     }   
    27 
    28     return 0;
    29 }

    -----------------------------------------------------------------------------
    memcpy功能是:两块内存之间拷贝数据。

    使用memcpy时,首先一定要确保内存没有重叠区域。

    void *memcpy(void *dest, const void *src, size_t n);
    第一个参数是:目标地址(目标内存首地址);
    第二个参数是:源地址(源内存首地址);
    第三个参数是:拷贝多少内容,单位字节。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main()
     5 {
     6     //把a的内容拷贝到b中去。
     7     int a[10] = { 1, 2, 3, 4 ,5 ,6 ,7 ,8 ,9, 10 };
     8     int b[10] = { 0 };
     9 
    10     memcpy(b, a, sizeof(a));
    11 
    12     int i;
    13     for (i = 0; i < 10; i++)
    14     {   
    15         printf("b[%d] = %d
    ", i, b[i]);
    16     }   
    17 
    18     return 0;
    19 }
    20 输出的结果是:
    21 b[0] = 1
    22 b[1] = 2
    23 b[2] = 3
    24 b[3] = 4
    25 b[4] = 5
    26 b[5] = 6
    27 b[6] = 7
    28 b[7] = 8
    29 b[8] = 9
    30 b[9] = 10

    --------------------------------------
    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main()
     5 {
     6     //把a的内容拷贝到b中去。将int改为short。
     7     short a[10] = { 1, 2, 3, 4 ,5 ,6 ,7 ,8 ,9, 10 };
     8     int b[10] = { 0 };
     9 
    10     memcpy(b, a, sizeof(a));
    11 
    12     int i;
    13     for (i = 0; i < 10; i++)
    14     {   
    15         printf("b[%d] = %d, %08x
    ", i, b[i], b[i]);
    16     }   
    17 
    18     return 0;
    19 }
    20 输出的结果是:
    21 b[0] = 131073, 00020001
    22 b[1] = 262147, 00040003
    23 b[2] = 393221, 00060005
    24 b[3] = 524295, 00080007
    25 b[4] = 655369, 000a0009
    26 b[5] = 0, 00000000
    27 b[6] = 0, 00000000
    28 b[7] = 0, 00000000
    29 b[8] = 0, 00000000
    30 b[9] = 0, 00000000

    内存拷贝说明画图如下:

    -----------------------------------------------------------------------------
    memmove功能是:内存移动,参数与memcpy一致。

    void *memmove(void *dest, const void *src, size_t n);
    第一个参数是:目标地址(目标内存首地址);
    第二个参数是:源地址(源内存首地址);
    第三个参数是:拷贝多少内容,单位字节。

    内存重叠区域说明如下图所示:

    =============================================================================

    指针小结

    定义             说明
    int i;         定义个一个int类型的变量
    int *p;       定义一个指向int类型的指针变量
    int a[10];       定义一个int类型的数组
    int *p[10];      定义一个指针数组,其中每一个数组元素指向一个int类型变量的地址
    int func();      定义一个函数,返回值类型为int类型
    int *func();     定义一个函数,返回值类型为int*类型
    int **p;      定义一个指向int类型的指针的指针,二级指针

    =============================================================================
    字符指针 与 字符串

    在c语言中,大多数的字符串操作其实就是指针操作。
    --------------------------------------
    1、通过指针访问字符串数组

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     char a[100] = "hello world";
     6     char *p = a;
     7 
     8     *p = 'a';   //注意:*p = p[0]
     9     p[3] = 'b';
    10     printf("%s
    ", a); //aelbo world
    11 
    12     return 0;
    13 }

    -----------------------------------------------------------------------------
    通过指针使得字符串逆置

    法一:使用一个指针
    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main()
     5 {
     6     char a[100] = "hello world";
     7     char *p = a;
     8 
     9     int len = strlen(a);
    10     int min = 0;
    11     int max = len - 1;
    12 
    13     while (min < max)
    14     {   
    15         //char tmp = *p;//等价于tmp = p[0];
    16         char tmp = *(p + min);
    17         *(p + min) = *(p + max);
    18         *(p + max) = tmp;
    19         max--;
    20         min++;
    21     }   
    22 
    23     printf("%s
    ", a); //dlrow olleh
    24 
    25     return 0;
    26 }

    --------------------------------------
    法二:使用二个指针
    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 int main()
     5 {
     6     char a[100] = "hello world";
     7     char *p = a;    //等价于 char *p; p = a;//p指向了数组的首元素的地址。
     8     char *p1 = a;   //等价于 char *p1 = p;
     9     
    10     int len = strlen(a);
    11 
    12     p1 += len - 1;//p1指向了数组的最后一个元素的地址。
    13     
    14     while (p < p1) 
    15     {   
    16         char tmp = *p; 
    17         *p = *p1;
    18         *p1 = tmp;
    19         p++;
    20         p1--;
    21     }   
    22 
    23     printf("%s
    ", a); //dlrow olleh
    24 
    25     return 0;
    26 }

    =============================================================================
    函数的参数为char *(即char *作为函数的参数)

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 //三者形式等价,钟爱第三种!
     4 //void test(char a[10])
     5 //void test(char a[])
     6 void test(char *a)    //数组作为函数的形参时,相当于一级指针。
     7 {
     8     printf("%s
    ", a); 
     9     a[3] = '4';
    10 }
    11 
    12 int main()
    13 {
    14     char a[] = "abcd";
    15     test(a);
    16     printf("%s
    ", a); 
    17 
    18     return 0;
    19 }
    20 输出结果是:
    21 abcd
    22 abc4

    如果将一个数组作为函数的形参进行传递,那么数组的内容可以在被调用函数的内部进行修改,
    有时候不希望这样的事情发生,所以要对形参采用const进行修饰。代码如下:

    1 void test(const char *a) 
    2 {
    3     printf("%s
    ", a); 
    4     //a[3] = '4';
    5 }

    -----------------------------------------------------------------------------
    自定义函数实现求字符串长度和字符串拷贝

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int mystrlen(const char *s) 
     4 {
     5     int len = 0;
     6     while (s[len])
     7     {   
     8         len++;
     9     }   
    10     return len;
    11 }
    12 
    13 void mystrcpy(char *s1, const char *s2)
    14 {
    15     int len = 0;
    16     while (s2[len])
    17     {   
    18         s1[len] = s2[len];
    19         len++;
    20     }   
    21 }
    22 
    23 int main()
    24 {
    25     char a[10] = "abc";
    26     char b[10] = { 0 };
    27 
    28     int i = 0;
    29     i = mystrlen(a);
    30     mystrcpy(b, a); 
    31     
    32     printf("%d
    ", i); 
    33     printf("%s
    ", b); 
    34     return 0;
    35 }
    36 输出的结果是:
    37 3
    38 abc

    -----------------------------------------------------------------------------
    如果一个数组作为函数的参数,那么数组的成员数量在函数内部是不可见的。
    解决方法:在传递一个数组的时候,需要同时提供另外一个参数,标明这个数组有几个成员变量。

    例外:如果函数的参数是一个字符串时,那么并不需要再传递一个参数说明这个字符串有多长。

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int printf_array(int n, int *a) 
     4 {
     5     int i;
     6     for (i = 0; i < n; i++)
     7     {   
     8         printf("%d
    ", a[i]);
     9     }   
    10 }
    11 
    12 int main()
    13 {
    14     int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    15     printf_array(sizeof(a) / sizeof(a[0]), a); 
    16     
    17     return 0;
    18 }
    19 
    20 注意:size_t 单位是1个字节。

    =============================================================================
    指针数组作为main函数的形参

    先来看一个指针数组作为函数的参数(此时把指针数组解释为二级指针)

    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 //int print(char *p[10])
     4 //int print(char *p[])
     5 int print(int n, char **p)  //指针数组作为函数的形参时,相当于二级指针。
     6 {
     7     int i;
     8     for (i = 0; i < n; i++)
     9     {   
    10         printf("%s
    ", p[i]);    //p[0]、p[1]、p[1]等的类型是char *。
    11         printf("%c
    ", *p[i]);    //*p[0]、*p[1]等的类型是char。
    12     }   
    13 }
    14 
    15 int main()
    16 {
    17     char *a[4];    //a[0]、a[1]、a[2]、a[3]分别指向一个char *类型的数组。
    18 
    19     char a1[] = "hello";
    20     char a2[] = "abc";
    21     char a3[] = "world";
    22     char a4[] = "haha";
    23 
    24     a[0] = a1; 
    25     a[1] = a2; 
    26     a[2] = a3; 
    27     a[3] = a4; 
    28         
    29     printf("%lu, %lu
    ", sizeof(a), sizeof(a[0]));
    30 
    31     print(sizeof(a) / sizeof(a[0]), a); 
    32 
    33     return 0;
    34 
    35 }
    36 输出结果是:
    37 32, 8
    38 hello
    39 h
    40 abc
    41 a
    42 world
    43 w
    44 haha
    45 h

    -----------------------------------------------------------------------------
    linux下示例代码如下:

     1 #include <stdio.h>
     2 
     3 int main(int argc, char **args)//argc代表这个数组有多少成员,args是一个指针数组,args这个数组的每个成员类型是char *,
     4 {
     5     int i;
     6     for (i = 0; i < argc; i++)
     7     {   
     8         printf("%s
    ", args[i]);
     9     }   
    10 
    11     return 0;
    12 }

    args是命令行参数的字符串数组,argc代表命令行参数的数量,程序名字本身就算一个参数。

    main函数是由系统调用的,所以main函数的参数功能是:得到命令行的参数。

    -----------------------------------------------------------------------------
    举个小例子:用到main函数的参数,实现计算两个数的和

    例如:

    程序名 数1 数2
    一回车结果就出来了。
    a 15 45
    60

    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main(int argc, char **args)    //注意:main函数的参数的类型、和顺序是不能修改的。
     5 {
     6     if (argc <= 2)
     7     {   
     8         printf("参数不足,使用方法:%s 整数1 整数2
    ", args[0]);
     9         return 0;
    10     }   
    11     else
    12     {   
    13         int a = atoi(args[1]);
    14         int b = atoi(args[2]);
    15         printf("%d
    ", a + b); 
    16     }   
    17 
    18     return 0;
    19 }

    -----------------------------------------------------------------------------
    课后作业
    写一个程序,需要用到main函数的参数

    例如:

    程序名 整数1 运算符 整数2,程序运行的结果是计算结果。
    a 5 + 6    注意:中间的加号是字符串。
    11

    a 5 * 6
    30

    ......

    + - * / 都要实现

    linux下示例代码如下:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main(int argc, char **args) //等价于 char *args[]
     5 {
     6     //因为星号在linux下是一个通配符,代表在当前目录下的所有文件。
     7 
     8     /*
     9     //验证星号是什么?
    10     int i;
    11     for (i = 0; i < argc; i++)
    12     {
    13         printf("%s
    ", argc[i]);
    14     }
    15     return 0;
    16     */
    17 
    18     if (argc < 4)
    19     {
    20         return 0;
    21     }
    22 
    23     //因为 char **args,是指针数组,args是二级指针,分别是 args[0]、args[1]等,类型是char *。
    24     int a = atoi(args[1]);  //把第一个参数转化为int。
    25     int b = atoi(args[3]);  //把第三个参数转化为int。
    26 
    27     //“+” 中间的加号是一个字符串。该字符串是一个字符数组,且对于该字符串的加号是第一个元素。
    28     char *s = args[2];  //得到第二个参数,因为每个参数的类型都是char *。
    29     char c = s[0];
    30     //char c = args[2][0];  //该句话与上面两句话等价。
    31 
    32     switch (c)
    33     {
    34         case '+':
    35             printf("%d
    ", a + b);
    36             break;
    37         case '-':
    38             printf("%d
    ", a - b);
    39             break;
    40         case '*':
    41             printf("%d
    ", a * b);
    42             break;
    43         case '/':
    44             printf("%d
    ", a / b);
    45             break;
    46         default:
    47             printf("error
    ");
    48     }
    49 
    50     return 0;
    51 }
    52 执行结果为:
    53 "p35.c" 51L, 1226C written                                                                                                                                              
    54 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# gcc -o a p35.c 
    55 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# a 6 + 5
    56 11
    57 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# a 6 - 5
    58 1
    59 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# a 6 * 5  (注意要有转义字符)
    60 30
    61 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# a 6 / 5
    62 1
    63 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# a
    64 root@iZ2zeeailqvwws5dcuivdbZ:~/1/01/指针# 

    =============================================================================

  • 相关阅读:
    ASP.NET的票据工具类FormsAuthenticationTicket
    FormsAuthenticationTicket学习笔记
    FormsAuthentication与Session超时时间不一的解决方法
    asp.net mvc 从数据库中读取图片的实现代码
    ASP.NET下载远程图片保存到本地的方法、保存抓取远程图片
    获取客户端的IP地址
    C#实现DNS解析服务
    Linux下安装Nginx详细图解教程
    手动配置Ubuntu Linux系列3-缺省网关和主机名
    web运维第一篇:nginx配置文件详解笔记
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/8215739.html
Copyright © 2011-2022 走看看