C 内存管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C 内存管理相关的知识,希望对你有一定的参考价值。

C 内存管理


一内存四区

代码区栈区堆区静态变量区


  作用域

    一个C语言变量的作用域可以是代码块 作用域函数作用域或者文件作用域。

代码块是{}之间的一段代码。

  auto自动变量

一般情况下代码块内部定义的变量都是自动变量。当然也可以显示的使用aotu关键字

  register寄存器变量

通常变量在内存当中如果能把变量放到CPU的寄存器里面代码执行效率会更高

register int I;

  代码块作用域的静态变量

静态变量是指内存位置在程序执行期间一直不改变的变量一个代码块内部的静态变量只能被这个代码块内部访问。

  代码块作用域外的静态变量

代码块之外的静态变量在程序执行期间一直存在但只能被定义这个变量的文件访问

  全局变量

全局变量的存储方式和静态变量相同但可以被多个文件访问

  外部变量与extern关键字

extern int I;

  全局函数和静态函数

在C语言中函数默认都是全局的使用关键字static可以将函数声明为静态

  内存四区

 

  代码区 

代码区code程序被操作系统加载到内存的时候所有的可执行代码都加载到代码区也叫代码段这块内存是不可以在运行期间修改的。


  静态区

所有的全局变量以及程序中的静态变量都存储到静态区,比较如下两段代码的区别

int a = 0;

int main()

{

static int b = 0;

printf("%p, %p\n", &a, &b);

return 0;

} int a = 0;

static int b = 0;

int main()

{

printf("%p, %p\n", &a, &b);

return 0;

}


  栈区

栈stack是一种先进后出的内存结构所有的自动变量函数的形参都是由编译器自动放出栈中当一个自动变量超出其作用域时自动从栈中弹出。

 

  堆区

堆heap和栈一样也是一种在程序运行过程中可以随时修改的内存区域但没有栈那样先进后出的顺序。

堆是一个大容器它的容量要远远大于栈但是在C语言中堆内存空间的申请和释放需要手动通过代码来完成。


14.3 堆的分配和释放

14.3.1 malloc


14.3.2 free











参数作用域

#include <stdio.h>
int main() 
{
        int *p = NULL; //其实是自动变量 auto int *p 
        {
                int i =100;
                p = &i;
        }
        //int arr[9] = {65535}; //这条语句可能覆盖刚释放的i的内存区域
        printf("%d \n",*p);  //不靠谱的操作因为上面代码作用域释放之后*p的指向很可能被其他变量占用
        return 0;
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
100 
#include <stdio.h>
int main() 
{
        int *p = NULL; //其实是自动变量 auto int *p 
        {
                int i =100;
                p = &i;
        }
        int arr[9] = {65535}; //这条语句可能覆盖刚释放的i的内存区域
        printf("%d \n",*p);  //不靠谱的操作因为上面代码作用域释放之后*p的指向很可能被其他变量占用
        return 0;
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
65535


静态变量是指内存位置在程序执行期间一直不改变的变量一个代码块内部的静态变量只能被这个代码块内部访

#include <stdio.h>
void fun()
{
        static int i = 0;
        printf("%d \n",i++);
}
int main() 
{
        fun();
        fun();
        fun();
        return 0;
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
0 
1 
2


栈大小

我的系统

[email protected]:~/pointer$ lsb_release -a
No LSB modules are available.
Distributor ID:Ubuntu
Description:Ubuntu 14.04.3 LTS
Release:14.04
Codename:trusty
[email protected]:~/pointer$ uname -rm
3.19.0-25-generic x86_



#include <stdio.h>
int main()
{
        char buf[8185 * 1024] = {};
}
不能比这个再大了就报错







堆内存的申请 与 释放

#include <stdio.h>
#include <stdlib.h>
int main()
{
        //int *p = (int *) malloc(sizeof(int));
        int *p = (int *) malloc(sizeof(char) *1024);
        *p = 200;
        printf("%d \n",*p);
        printf("%p \n",p);
        free(p);//请记得释放内存
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
200 
0x7f158cec7010



堆指针变化方向

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
        while (1)
        {
                int *p = malloc(1024*1024*100);
                printf("%p \n",p);
                sleep(1);
        }
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
0x7fd62f15d010 
0x7fd628d5c010 
0x7fd62295b010 
0x7fd61c55a010 
0x7fd616159010 
0x7fd60fd58010 
0x7fd609957010



函数返回字符串问题

#include <stdio.h>
#include <stdlib.h>
char *test()
{
        char str[] = {"Hello Wold!"};
        return str;
}
int main()
{
        char *p = test();
        printf("%s \n",p);
}
main.c:6:2: warning: function returns address of local variable [-Wreturn-local-addr]
  return str;
  ^
¤@ 
并不会得到期望的字符串


这样为什么是可以返回的呢因为字符串是常量

#include <stdio.h>
#include <stdlib.h>
char *test()
{
        return "Hello World !";  //因为这是常量
}
int main()
{
        char *p = test();
        printf("%s \n",p);
}



堆内存 与 函数调用解决方式

因为如果在函数内部申请空间将处理之后的存储堆内存中的字符串返回的时候是无法释放的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char test(char **p)
{
        *p = malloc(sizeof(char) *20); //改变原一级指针指的地址
        printf("%p   p \n",p);
        printf("%p  *p \n",*p);
}
int main() 
{
        char *s = NULL;
        test(&s);
        strcpy(s,"Hello World!");
        printf("%s \n",s);
        printf("%p  s \n",s);
        free(s);
}
[email protected]:~/pointer$ gcc -std=c99 main.c && ./a.out
0x7fffcc6b0dc8   p 
0x76b010  *p 
Hello World! 
0x76b010  s
























本文出自 “魂斗罗” 博客,请务必保留此出处http://990487026.blog.51cto.com/10133282/1775750

以上是关于C 内存管理的主要内容,如果未能解决你的问题,请参考以下文章

按位或运算符 | C中用于对齐内存块的用法[重复]

C 内存管理

C/C++ 内存管理总结

如何使用模块化代码片段中的LeakCanary检测内存泄漏?

C程序存储结构

iPhone应用程序中C代码的内存管理