美文网首页
C语言指针与内存

C语言指针与内存

作者: KevinCool | 来源:发表于2016-08-30 23:18 被阅读122次
    • 初始指针
      使用指针来进行交换值
    #include<stdio.h>
    void change(int *a,int *b){
        int tmp=*a;
        *a = *b;
        *b = tmp;
    }
    int main(){
        int a=5,b=3;
        change(&a,&b);
        printf("num a = %d\nnum b = %d\n",a,b);
        return 0;
    }```
    - gdb调试工具
    `brew install gdb`
    调试的时候,生成可以调试的版本,`gcc -g main.c -o main.out`
    `gdb ./main.out`对程序进行调试,Mac里面必须是这样`sudo gdb ./main.out`才能对程序进行调试。
    `l`列出源代码,按回车继续刚才的命令
    `break 12`断点放在12行
    `start`单步调试
    `n`下一步
    `p a`打印出a的变量值
    `q`退出
    `s`进入函数里面
    `bt`查看函数堆栈
    `f 1`跳到1这个栈里面
    - 计算机中的数据表示方法
    计算机中内存中最小单位是字节,1Byte字节=8bit位
    - 内存管理
    操作系统统一管理,32bit系统,最大使用4G内存,由寻址空间决定的,地址总线是32位,寻址空间是32位,也就是给内存编号只能有32位。
    地址总线可以存在多种状态,2^32个状态,所以就是2^32字节,4GB,64位操作系统,64位的地址总线,所以内存足够了,操作系统会给内存地址进行编号,编号就是唯一的内存字节的地址,一个字节存放8个二进制位的数据。
    64位操作系统中,用户应用程序使用的内存只要有前面的48位就够了,其他的内存空间是给操作系统内核使用的
    高位内存:系统内核->栈->堆->数据段->代码段:低位内存
    代码编译后的二进制数据加载到内存中,代码段
    声明的全局变量和一些常量在数据段
    中间的区域是自由可分配的内存
    - 变量和指针的本质
    静态变量,静态局部变量,作用域是当前函数,从定义位置,到其所在的{}结束位置,生命周期是从程序运行到程序退出,贯穿整个运行时间,下次函数调用的时候,静态局部变量不会再次初始化,而是沿用上次函数退出时的值。
    静态全局变量,作用域为当前文件,从定义位置到文件结尾,声明周期为从程序运行到程序退出,贯穿整个运行时间,但是动态全局变量的作用域是整个项目,即最终编译成可执行文件的所有文件均可以使用动态全局变量。
    C语言语法是不允许直接操作代码段的,代码段也是有地址的,除了代码编译后存在代码段外,代码的状态信息是存在内存的栈区域。
    C语言是强类型,静态类型的。
    变量的本质是一个代号,标识符,代表的是某个地址空间
    指针本身也是一个变量,保存的数据是地址,指针变量的地址也就是指针的指针。指针的本质是保存内存地址。
    - 操作系统对内存的管理
    编译器的优化功能,对源代码进行优化,将同一类型的变量内存地址分配在一块,使得程序执行更快。64位系统中指针是8个字节,因为地址总线是64位的。
    栈的内存空间保存了程序运行时候的状态。
    代码段的内存地址是向上增长分配的,然后栈段的内存地址是从大往小进行分配的。
    - 函数栈以及数据段内存
    栈里最先分配地址的函数内存地址更大一些,静态变量,常量还有全局变量默认是在数据段中,静态变量属于某个函数特定的,一个函数被多次调用,但是都在数据段中。
    - 函数指针与指针指向的数据访问
    `int (*pquadrate)(int a) = &quadrate;`定义一个函数指针
    `int s = (*pquadrate)(a);`使用这个函数指针,()表示地址指向某个函数整体,然后后面调用传参数a。如果指向栈内存,数据段内存表示直接去变量里面的值,指向代码段,就是一片代码块。
    - 示例代码
    

    include<stdio.h>

    int global = 0;
    int rect(int a,int b){
    static int count = 0;
    count++;
    global++;
    int s = a * b;
    return s;
    }
    int quadrate(int a){
    static int count = 0;
    count++;
    global++;
    int s = rect(a,a);
    return s;
    }
    int main(){
    int a = 3;
    int b = 4;
    int *pa = &a;
    int *pb = &b;
    int pglobal = &global;
    int (
    pquadrate)(int a) = &quadrate;
    int s = quadrate(a);
    printf("%d\n",s);
    }```

    • 数组申明的内存排列
      x/3d 0x7fffffffde14从这个地址开始显示3个十进制,默认是按照4字节显示
      这里经过gcc优化,b的地址在最前面,其次是a,但是i的地址在$10 = (int *) 0x7fff5fbffc54, b的地址$9 = (int *) 0x7fff5fbffc60,a的地址$8 = (int *) 0x7fff5fbffc64,array的地址$12 = (int (*)[3]) 0x7fff5fbffc6c,说明这些变量之间的地址分配还不是连续的,但是数组间的地址分配是连续的。
    #include<stdio.h>
    int main(){
        int a = 3;
        int b = 2;
        int array[3];//必须是常量
        array[0] = 1;
        array[1] = 10;
        array[2] = 100;
        int *p = &b;
        int i;
        for(i = 0;i < 6;i++){
            printf("*p = %d\n",*p);
            p++;
        }
        printf("------------------------\n");
        p = &b;
        for(i = 0;i<6;i++){
            printf("p[%d]=%d\n",i,p[i]);
        }
        return 0;
    }```
    - 指针运算
    `p++`定义了p是int类型,所以大小是4字节,自增就是到下一个4字节的地址。
    `p[1]`表示把p向下偏移4个字节
    指针是变量,数组是指针常量,数组本身也是地址。
    - 字符数组和指针字符串
    

    include<stdio.h>

    int main(){
    char str[] = "hello";
    char *str2 = "world";
    char str3[10];
    printf("input the value\n");
    scanf("%s",str3);
    printf("str is %s\n",str);
    printf("str2 is %s\n",str2);
    printf("str3 is %s\n",str3);
    }```
    str2在代码段,str2是指向这个地址而已,字符类型的指针,字符数组str3本身就是内存地址。str2指向字符串的指针,不能向里面scanf,str2是存的world字符串的地址,在代码段的地址,不能被修改,而str是字符数组的地址,str地址是在栈里面,字符数组是以\0为结尾。x/6cb 0x7ffffffde00打印6个字符,单字节显示。
    栈和堆内存才能被写入。

    • 字符数组
      str[3]='\0'表示字符串结束位置,str2指向的是常量字符串,所以不能被修改

    相关文章

      网友评论

          本文标题:C语言指针与内存

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