C_指针

当年刚开始接触C语言看郝斌的视频做的笔记,好歹也是自己辛苦敲出来的,所以一定要发出来。都是一些最基础的C语言指针知识。

一、认识指针

# include <stdio.h>

int main(void)
{
    int * p;    //p是变量的名字,int * 表示p存放的是int类型变量的地址
    int i = 3;
    int j;

    p = &i;
    /*
        1.p保存了i的地址,因此p指向i
        2.p不是i,i也不是p,更准确的说,修改p的值不影响i的值,修改i的值不影响p的值
        3.如果一个指针变量指向了某个普通变量,则
            *指针变量 将完全等同于 普通变量
          例子:
                如果p是个指针变量,并且p存放了普通变量i的地址
                则p指向了普通变量i
                *p 就完全等同于 i
                或者说:在所有出现*p的地方都可以替换成i
                        在所有出现i的地方都可以替换成*p
                *p就是以p的内容为地址的变量
    */
    j = *p;

    printf("i = %d, j = %d\n", i, j);

    return 0; 
}

/*
指针的重要性
    表示一些复杂的数据结构
    快速的传递数据,减少内存的耗用
    使函数返回一个以上的值
    能直接访问硬件
    能够方便的处理字符串
    是理解面向对象语言中的引用基础

   指针是C语言的灵魂
*/

二、基本类型指针常见错误

# include <stdio.h>

int main(void)
{
    int i = 5;
    int * p;
    int * q;

    p = &i;
    //*q = p;   //error
    //*q = *p;  //error
    p = q;  //q是垃圾值,q赋给p,p也变成垃圾值

    printf("%d\n", *q); //13行
    /*
        q的空间属于本程序的,所以本程序可以读写q的内容
        但是如果q内部是垃圾值,则本程序不能读写*q的内容
        因为此时*q所代表的内存单元的控制权限没有分配给本程序
        所以本程序运行到13行是就会立即出错
    */

    return 0;
}

三、经典指针程序_互换两个数字

# include <stdio.h>

void huhuan_1(int, int);
void huhuan_2(int *, int *);
void huhuan_3(int *, int *);

int main(void)
{
    int a = 3;
    int b = 5;

    huhuan_3(&a, &b);

    printf("a = %d, b = %d\n", a, b);

    return 0;
}

//不能完成互换功能
void huhuan_1(int a, int b)
{
    int t;
    t = a;
    a = b;
    b = t;

    return;
}

//不能完成互换功能
void huhuan_2(int * p, int * q)
{
    int * t;

    t = p;
    p = q;
    q = t;

    return;
}

//可以完成互换功能
void huhuan_3(int * p, int * q)
{
    int t;

    t = *p;
    *p = *q;
    *q = t;

    return;
}

/*
如何通过被调函数修改主调函数普通变量的值
    1. 实参必须为该普通变量的地址
    2. 形参必须为指针变量
    3. 在被调函数中通过
            *形参名 = ......
       的方式就可以修改主调函数相关变量的值
*/

四、一维数组与指针

# include <stdio.h>

int main(void)
{
    int a[5];   //a是数组名,5是数组元素的个数,元素就是变量,a[0]--a[4]
    int b[4];

    //a = b;    //error,因为a是常量

    printf("%#X\n", &a[0]);     //%#X 是一十六进制输出
    printf("%#X\n", a);

    return 0;
}

/*
在vc++6.0中的显示结果为:
-------------------------
0X19FF2C
0X19FF2C
-------------------------
总结:
一维数组名
        一维数组名是一个指针常量
        她存放的是一维数组第一个元素的地址
*/

五、确定一个一维数组需要2个参数

# include <stdio.h>

void f(int * pArr, int len)
{
    int i;

    for (i=0; i<len; i++)
        printf("%d\t", *(pArr + i)); //*(pArr + i) 等价于 pArr[i]
    printf("\n");

    return;
}

int main(void)
{
    int a[5] = {1,2,3,4,5};
    int b[6] = {-1,-2,-3,-4,-5,-6};
    int c[100] = {23,4,4,6,66,43};

    f(a, 5);
    f(b, 6);
    f(c, 100);

    return 0;
}

/*
确定一个一维数组需要两个参数
    数组第一个元素的地址
    数组的长度
*/

五、确定一个一维数组需要2个参数_2

# include <stdio.h>

void f(int * pArr, int len)
{
    pArr[3] = 88;

    return;
}

int main(void)
{
    int a[6] = {1,2,3,4,5,6};

    printf("%d\n", a[3]);

    f(a, 6);
    printf("%d\n", a[3]);

    return 0;
}

/*
一定要明白 pArr[3] 和 a[3] 是同一个变量

  在vc++6.0中的显示结果为:
  ------------------------
  4
  88
  ------------------------
*/

六、动态内存分配【重难点】_传统数组的缺点

动态内存分配
    传统数组的缺点:
        1.数组长度必须事先制定,且只能是常整数,不能是变量
            例子:
                 int a[5];  //ok
                 int len; int a[len];   //error

        2.传统形式定义的数组,该数组的内存程序员无法手动释放,
          在一个函数的运行期间,系统为该函数中数组所分配的空间会一直存在,
          直到该函数运行完毕时,数组的空间才会被系统释放。

        3.数组的长度一旦定义,其长度就不能再改变
          数组的长度不能再函数的运行过程中动态的扩充或缩小

        4.A函数定义的数组,在A函数运行的期间可以被其他函数使用,
          但A函数运行完毕后,A函数中的数组将无法再被其他函数使用
          传统方式定义的数组不能跨函数使用

    为什么需要动态分配内存
        动态数组很好的解决了传统数组的这4个缺陷
        传统数组也叫静态数组

七、malloc函数使用的简单介绍_1

/*
malloc 是 memory(内存)allocate(分配)的缩写
*/

# include <stdio.h>
# include <malloc.h>

int main(void)
{
    int i = 5;  //10行
    int * p = (int * )malloc(4);    //11行
    /*
        1.要使用malloc函数,必须添加malloc.h这个头文件
        2.malloc函数只有一个形参,并且形参是整型
        3.4表示请求系统为本程序分配4个字节
        4.malloc函数只能返回第一个字节的地址
        5.11行分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节
        6.p本身所占的内存是静态分配的,p所指向的内存是动态分配的
    */
    *p = 5;     //*p代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和10行的i变量分配方式不同

    free(p);    
    /*free(p)表示把p所指向的内容给释放掉,p本身的内存是静态分配的,本能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放*/
    printf("哈哈!\n");

    return 0;
}

八、malloc函数使用的简单介绍_2

# include <stdio.h>
# include <malloc.h>

void f(int * q)
{
    //*p = 200; //error
    //q = 200;  //error
    //**q = 200;//error
    *q = 200;
    //free(q);  //把q所指向的内存释放掉,本语句必须注释掉,否则会导致第23行代码出错
}

int main(void)
{
    int * p = (int * )malloc(sizeof(int));  //sizeof(int)返回值是int所占的字节数
    *p = 10;

    printf("%d\n", *p);

    f(p
        );  //p是int * 类型

    printf("%d\n", *p);

    return 0;
}

九、动态内存分配举例_动态一维数组的构造

# include <stdio.h>
# include <malloc.h>

int main(void)
{
    int a[5];   //如果int占4个字节的话,则本数组总共占了20个字节,每4个字节被当做了一个int变量来使用
    int len;
    int * pArr;
    int i;

    //动态的构造一维数组
    printf("请输入你要存放的元素个数:");
    scanf("%d", &len);
    pArr = (int * )malloc(4 * len); //本行动态的构造了一个一维数组,该一维数组的长度是len,该数组的数组名为pArr,该数组的每个元素是int类型,类似于int pArr[len]

    //对一维数组进行操作, 如对动态一维数组进行赋值
    for (i=0; i<len; ++i)
        scanf("%d", &pArr[i]);

    //对一维数组进行输出
    for (i=0; i<len; ++i)
        printf("%d\n", pArr[i]);

    free(pArr); //释放掉动态分配的数组

    return 0;
}

十、多级指针

# include <stdio.h>

int main(void)
{
    int i = 10;
    int * p = &i;
    int ** q = &p;
    int *** r = &q;

    //r = &i;   //error 因为r是int *** 类型,只能存放int **类型变量的地址

    printf("i = %d\n", ***r);

    return 0;
}

/*
    i       p       q       r
 -----   -----   -----   -----
  10     1000h   2000h   3000h
 -----   -----   -----   -----
 1000h   2000h   3000h   4000h
 int    int *   int **  int ***
*/

十一、动态内存可以跨函数使用详解

# include <stdio.h>
# include <malloc.h>

void f(int ** q)
{
    *q = (int *)malloc(sizeof(int));    //等价于 p = (int *)malloc(sizeof(int));

    **q = 5;    //**q = *p;
}

int main(void)
{
    int * p;

    f(&p);

    printf("%d\n", *p);

    return 0;
}

十二、指针变量不能跨函数使用详解

# include <stdio.h>

void f(int ** q)    //q是个指针变量,无论q是什么类型的指针变量,都只占4个字节
{
    int i = 5;

    *q = &i;    //*q等价于p,p = &i;
}

int main(void)
{
    int * p;

    f(&p);

    printf("%d\n", *p); //本语句语法没有问题,但逻辑上有问题

    return 0;
}

/*
f终止之后,为f分配的静态变量全部释放
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值