zhliao2

风雨兼程,一路向北-------fpga (Keep a quiet heart study)
c指针

大一记载的笔记:

 动态内存和静态内存的比较
    静态内存是有系统自动分配,由系统自动释放
    静态内存是在栈分配的

    动态内存是由程序员手动分配, 手动释放
    动态内存是在堆内存分配的


地址一般用十六进制表示(H) 
 指针就是地址, 地址就是指针
 地址就是内存单元的编号,不是编码。
 指针变量是存放地址的变量
 指针和指针变量是两个不同的概念
 但是要注意:通常我们叙述时会把指针变量简称为指针, 实际他们的含义并不一样
附注:
    1:乘法
    2:定义指针变量
          int * p
            //定义了一个名字叫p的变量, int *表示p只能存放int变量的地址
    3:指针运算符
    该运算符放在已经定义好的指针变量的前面
    如果p是一个已经定义好的指针变量
    则*p表示 以p的内容为地址的变量 // 重要
 如何通过被调函数修改主调函数的普通变量的值
    1. 实参必须为该普通变量的地址
    2. 形参必须为指针变量
    3. 在被调函数中通过
        *形参名 = 。。。。
         的方式就可以修改主调函数相关变量的值
指针:
      指针的重要性
           表示一些复杂的数据结构
            快速的传递数据
         使函数返回一个以上的值
       能直接访问硬件
       能够方便的处理字符串
       是理解面向对象语言中引用的基础
 

 指针的定义
      地址
       内存单元的编号
      从零开始的非负整数
      范围:4g (0--4g-1)
   
       指针
           地址一般用十六进制表示(H) 
         指针就是地址, 地址就是指针
        地址就是内存单元的编号
       指针变量是存放地址的变量
       指针和指针变量是两个不同的概念
        但是要注意:通常我们叙述时会把指针变量简称为指针, 实际他们的含义并不一样
           指针的本质就是一个操作受限的非负整数
       


 指针的分类
     1. 基本类型的指针
     2. 指针和数组
        指针和一维数组名
            一维数组名是个指针常量
            它存放的是一维数组的第一个元素的地址
        下标和指针的关系
            如果p是个指针变量,则
                p[i]永远等价于*(p + i)  //知识要点
        确定一个一维数组需要几个参数【如果一个函数要处理一个一维数组,则需要接受该数组哪些信息】
            需要两个参数:
                数组的第一个元素的地址
                数组的长度
                
        指针的运算       

        指针变量的的运算
            指针变量不能相加 不能相乘 也不能相除
             如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才能相减
        一个指针变量到底占几个字节【非重点】
            预备知识:
                sizeof(数据类型)
                功能:返回值就是该数据类型所占的字节数
                例子:sizeof(double) = 8
                sizeof(变量名)
                功能:返回值是该变量所占的字节数


            假设p指向char类型变量(1个字节)
            假设q指向int类型变量(4个字节)
            假设r指向double类型变量(8个字节)
            p q r 本身所占的字节数是否一样?
                答案:是


            总结:
                一个指针变量,无论它指向的变量占几个字节该指针变量值占四个字节

                一个变量的地址使用该变量的首字节的地址来表示
                

       指针和和二维数组

     3. 指针和函数
     4. 指针和结构体
     3. 多级指针

   专题:
    动态内存分配
        传统数组的缺点:
            1:数组的长度必须事先制定,且只能是长整数,不能是变量
                例子:
                    int a[5]; //ok
                    int len = 5; int a[len]; //error
            2: 传统形式定义的数组,该数组的内存程序员无法手动释放
               在一个函数运行期间, 系统为该函数中数组所分配的空间会一直存在, 直到该函数运行完毕时,数组的空间才会被系统释放

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

            4: A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用   传统方式定义的数组不能跨函数使用
                 
            
            
    
        为什么需要动态分配内存
            动态数组很好的解决了传统数组的这4个缺陷
            传统数组也叫静态数组

        动态内存分配的举例_动态数组的构造

        静态内存和动态内存的比较

        跨函数使用内存的问题



         

  1


# include <stdio.h>


int main(void)
{
    int *p;  //p是变量的名字, int *表示p变量存放的是int类型变量的地址
    int i = 3;
    p = &i;  //ok
        //p = 55; //error;
    //p = i;  //error 因为类型不一致, p只能存放int类型变量的地址
}
     


     

     2


# include <stdio.h>


int main(void)
{
    int * p;  //p是变量的名字, int *表示p变量存放的是int类型变量的地址
            //int *p;不表示定义了一个名字叫做*p的变量
            //int *p;应该这样理解:p是变量名, p变量的数据类型是int *p类型
            //         所谓int *;类型实际就是存放int变量地址的类型
    
    int i = 3;
    p = &i;  
             /*  1. p保存了i的地址, 因此p指向了i
                 2.p不是i, i也不是p, 更准确的说:修改了p的值不影响i的值修改了i的值也不影响p的值
                 3.如果一个指针变量指向了某个普通变量,则
                   *p 就完全等同义 普通变量

                    例子:
                         如果p是个指针变量, 并且p存放了普通变量i的地址
                         则p指向了普通变量i
                         *p 就完全等同于 i
                         或者说:在所有出现了*p的地方都可以替换成i
                                 在所有出现i的地方都可以替换成*p
                          *p就是以p的内容为地址的变量
                  */
}





     3


# include <stdio.h>

int main(void)
{
    int i = 5;
    int *p;
    
    *p = i;//error p的地址不明确   //加上p = &i程序就不会出错,

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


     


    4


# 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);
                /*
                    q的空间是属于本程序的, 所以本程序可以读写q的内容,
                    但是如果q内部是垃圾值, 则本程序不能读写*q的内容
                    
                */
}




    5


# include <stdio.h>


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

    t = a;
    a = b;
    b = t;

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





    6

//互换不了a和b的值

# include <stdio.h>
void huhuan(int a, int b)
{
    int t;
    t = a;
    a = b;
    b = t;
    return;
}


int main(void)
{
    int a =4, b = 6;
    huhuan(a, b);
    printf("a = %d, b = %d\n", a, b);
}




    7

//互换不了a和b的值
//函数void huhuan(int * p, int * q)中的功能是交换了p和q的值,而不是a和b的值

# include <stdio.h>
void huhuan(int * p, int * q)
{
    int * t;  //如果要互换p和q的值,则必须是int *, 不能是int, 否则会出错
    t = p;
    p = q;
    q = t;
}


int main(void)
{
    int a = 45, b = 3;
    huhuan(&a, &b);  //huhuan(*p, *q);是错误的,huhuan(a, b);也是错误的,因为是类型不一致
    printf("a = %d, b = %d\n", a, b);
}






    8

//互换得了a和b的值

# include <stdio.h>
void huhuan(int * p, int * q)
{
    int  t;  //如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法错误
    
    t = *p;   //p是int *, *p是int
    *p = *q;
    *q = t;
}


int main(void)
{
    int a = 45, b = 3;
    huhuan(&a, &b);  //huhuan(*p, *q);是错误的,huhuan(a, b);也是错误的
    printf("a = %d, b = %d\n", a, b);
}





     9

# include <stdio.h>

int main(void)
{
    int i = 45;
    char ch = 'A';
    int * p; //等价于int *p;也等价于int* p;
    p = &i;  //*p是以p的内容为地址的变量
    *p = 99;
    printf("i = %d, *p = %d\n", i, *p);   //注意了, 两者输出的值都是99;与上一行有和关联呢?。。。
    //p = &ch
    //p = ch;//error
    //p = 5;//error
    return 0;
}



     10


# include <stdio.h>
int f(int j)
{
    int i = 99;
    return i;
}


int main(void)
{
    int i;
    i = 66;
    printf("i = %d\n", i);
    f(i);
    printf("i = %d\n", f(i));
}




    11
//使函数返回一个以上的值
// ab的值变成了void f(int * p, int * q)里面的值
# include <stdio.h>
void f(int * p, int * q)
{
    *p = 35;
    *p = 77;
}

int main(void)
{
    int a = 5, b = 66;
    f(&a, &b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}




   12


# include <stdio.h>

int main(void)
{
    int a[5];
    int b[5];
    //int a[3][4];// a[i][j]
    //a = b; //error //a是常量
    printf("%#X", &a[0]);
    printf("%#x", a);
}





    13

# include <stdio.h>

//f函数可以输出任何一个一维数组的内容
void f(int *pArr, int len)
{
    int i;
    for(i = 0; i < len; i ++)
    {
        printf("%d", * (pArr + i));//p[i]永远等价于*(p + i)
}
    }
    printf("\n");
}

int main(void)
{
    int a[5] = {1, 3, 4, 5, 6};
    int b[7] = {5, 6, 7, 8, 8};
    int c[15] = {57, 78, -4, 889, 90};
             //a = a[4]; //error  //因为a是长量
    f(a, 5);    //a是int *
    f(b, 7);
    f(c, 15);
    return 0;
}




    14


//要明白pAr[3] 和 a[3] 是同一个变量
# include <stdio.h>
void f(int *pArr, int len)
{
    pArr[3] = 88;  //等价于*(pArr + 3),  也等价于*[a + i], 也等价于a[i]  //重点:p[i]永远等价于*(p + i)  
}

int main(void)
{
    int a[6] = {1, 3, 4, 5, 6, 7};
    printf("%d\n", a[3]);
    f(a, 6);
    printf("%d\n", a[3]);
     return 0;
}



     

      15
//修该了i的值

# include <stdio.h>

void f(int * i)
{
    *i = 34;
}

int main(void)
{
    int i = 8;
    printf("i = %d\n", i);
    f(&i);
    printf("i = %d\n", i);
}




    16

//指针的运算
# include<stdio.h>

int main(void)
{
    int i = 5;
    int j = 10;
    int * p = &i;
    int * q = &j;
    int a[5];
    p = &a[1];
    q = &a[4];
    printf("p和q所指向的单元相隔%d个单元\n", q - p);
    
}




   17

//指针的运算
# include<stdio.h>

int main(void)
{
    int i = 5;
    int j = 10;
    int * p = &i;
    int * q = &j;
    //p - q没有实际意义
}



   18


# include <stdio.h>

int main(void)
{
    int i = 5;
    char ch = 'a';
    double j = 56.5;
    int * p;
    char * q;
    double * z;
    p = &i;
    q = &ch;
    z = &j;
    printf("%d, %d, %d\n", sizeof(p), sizeof(q), sizeof(z));
}




    19



# include <stdio.h>

void g(int * pArr, int len)
{
    pArr[2] = 88;
}

void f()         //f()函数中止后, 函数里面的数组就不能被其他函数使用了, 因为它已经释放掉了
{
    int a[5] = {1, 2, 3, 4, 5};//20个字节的存储空间程序员无法手动编程释放它,
                               //它只能在本函数运行完毕是由系统自动释放
    g(a, 5);
    printf("%d\n", a[2]);
}

int main(void)
{
    f();
    return 0;
}




   20


//malloc 是memory(内存)  allocate(分配)的缩写
# include <stdio.h>
# include <malloc.h>

int main(void)
    int i = 5;  //分配了4个字节  静态分配  //11
    int * p = (int *)malloc(4);  //12
    /*
        1. 要使用malloc函数, 必须添加malloc.h这个头文件
        2. malloc函数只有一个形参, 并且形参是整型
        3. 4表示请系统为本程序分配4个字节
        4. malloc函数只能返回第一个字节的地址
        5. 12分配了8个字节, p变量占4个字节, p所指向的内存也占4个字节
        6. p本身所占的内存是静态分配的, p所指向的内存是动态分配的
    */
    *p = 5; //*p 代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和11的i的分配方式不同
    free(p);//free(p)表示把p所指向的内存给释放掉  p本身是静态的, 不能有程序员手动释放,p本身的内存只能在p变量所在的函数运行终止是由系统自动释放
    printf("好啊\n");
}




   21


# include <stdio.h>
# include <malloc.h>
void f(int * q)
{
    //* p = 200;//error
    //q = 300;//error
    //** p = 4304; //error
    * q = 200;
    //free(q) // 必须注释掉,否则,第二个printf会出现错误
}

int main(void)
{
    int * p = (int *)malloc(sizeof(int));//sizeof(int)返回值是int所占的字节数
    * p = 10;
    printf("%d\n", * p);
    f(p);
    printf("%d\n", * p);
    return 0;
}




    22


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

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

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

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

    //对一维数组的内容进行输出
    printf("一维数组的内容是:\n");
    for(i = 0; i < len; i ++)
        printf("%d\n", pArr[i]);
    //free(pArr); //释放掉动态分配的数组   //补充:pArr当初是指向50个字节,当执行realloc(pArr, 100); pArr指向了100个字节
    return 0;
}




   23
//多级指针


# include <stdio.h>

int main(void)
{
    int i = 20;
    int * p = &i;
    int ** q = &p;
    int ***r = &q;
    //r = &p;  //error  
    printf("i = %d\n", ***r);
    return 0;
}



    24
# include <stdio.h>

void f(int ** q)
{
    //*q 就是p
}

void g()
{
    int i = 10;
    int * p = & i;
    
    f(&p); // p是int类型, &p就是int **类型
}

int main(void)
{
    g();
    return 0;
}





  25



# include <stdio.h>

void f(int ** q)
{
    int i = 5;
    //*q 等价于p q和**q都不等价于p
    //*q = i;//error 因为*q = i; 等价于p = i; 这样写是错误的
    *q = &i; // p = &i;
}

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

    return 0;
}





     26

//动态内存可以跨函数使用
# include <stdio.h>
# include <malloc.h>

void f(int ** q)
{
    * q = (int *)malloc(sizeof(int));
    //* q = 5;// p = 5;
    //q = 5;//error;
    ** q = 8;//* p = 8;
}

int main(void)
{
    int * p;
    f(&p);
    printf("%d\n", * p);
}

posted on 2012-06-09 02:03  zhliao  阅读(295)  评论(0)    收藏  举报