C语言整理-10

来源:互联网 发布:新大洋知豆 编辑:程序博客网 时间:2024/06/05 08:46

动态内存分配

存储区的划分:

在计算机的内存中,可以分成5个区,每个区都有着不一样的效果。按内存编号从小到大的顺序,分别是:

(1)、代码区:

计算机将我们写的代码通过二进制转换后,放进了这个代码区。

(2)、常量区:

在我们写代码时,所有的常量,都放在常量区,常量区的所有值都是可读不可写的。也就是说,常量区的所有值都是不能改变的。若强行对其赋值,则在运行的时候,直接导致程序崩溃。

常用的一个关键字:const。

const可以把一个变量声明成常量:constint i = 10; 此时,就应该把num1当成常量来使用。此时再给num1赋值,会报错。如果用指针取到num1的地址,然后再用 * 取值后给其赋其他值,虽然可以成功赋值,但是此时的num1已经不是原来的num1,而是原来的num1用const修饰后,直接转移到了常量区,用指针取地址后,取到的是num1在栈区的地址,改动的也是原来栈区内的num1。也就说,有两个num1,一个在常量区,一个在栈区。因此,为了保证安全,不能这样写。

//    常量区

   

//    程序中出现的所有常量,保存到常量区

//    常量区的所有值:只读不可写   

//    const

//    可以将变量声明成常量   

//    int num1 = 10;

//    num1 = 20;//可以改值

//    //const的意思:只读,num1的值不能改变了。

//    const int num1 = 10;//定义成常量,要当做常量使用。

//    num1 = 20;//报错

    //不要这样写。这样写会破坏安全性。

//    int *pi = &num1;

//    *pi = 20;

    //num1的值在常量区有一份,在栈区有一份。

//    printf("%d\n",num1);//10,这个num1已经放到了常量区。

//    printf("%d\n",*pi);//20,这个值是num1的值,但是这个num1的位置是在栈区。

   

    //const放在不用的位置,效果不一样(作业)

//    const int *p = NULL;

 

 

(3)、静态区:

用来存放静态值的地方。在代码中,用static来标记。用static来标记的语句,在整个程序运行过程,只进行一次初始化,不论程序是否循环到该语句,都不再执行。如果初始化的时候,没有给初始值,系统会自动给0。静态区的东西常驻内存,直到程序运行结束才会释放。全局变量也放在静态区,也叫全局区。这个时候,其他文件可以用到这个全局变量。此时,如果我们在这个全局变量加上static修饰,这时候的static会限制作用域,限制其他文件不能用。static 依然受到作用域的约束。

#import <Foundation/Foundation.h>

//也在静态区,也叫做全局区

//int n2 = 10;

//如果全局变量加了static会限制作用域,其他文件不能使用。

staticint n2 =10;

 

//静态区的变量,可以不做初始化,自动清0.

//可以计数使用

int test(){

    staticint count = 0;

    return ++ count ;

}

 

int main(int argc,constchar * argv[]){

 //静态区

//    static int num = 10;

//    printf("%d\n",num);

//   

//    num = 20;

//   

//    printf("%d\n",num);

   

//    while (1) {

//        int i = 0;

//        printf("%d\n",i++);//全部打印0

//    }

//    while (1) {

//        //静态变量只被初始化一次。

//        static int i = 0;//这条语句执行过一次后,这条语句就失效了,不再执行

        printf("%d\n",i++);//全部打印0

    }

    //依然受作用域的约束

    i = 10;//报错   

    printf("%d\n",test());//1

    printf("%d\n",test());//2

    return 0;

}

(4)、堆区:

用malloc等函数分配的内存。

堆区是唯一一个由我们自己可以掌管内存大小,并对内存回收的区。即:⼿动分配,⼿动释放。

堆,是内存中,最大的一块。因此,大部分情况下,类型的内存申请是在堆中完成的。

malloc函数:动态分配内存函数:void*malloc();

void * 表示任意指针类型。也就是返回值可以是任意类型的指针。

括号内的参数,意思是分配多少字节的大小。

    //参数的意思是:写多少,就分配几个字节的内存。

    //void *任意指针类型

//    char *p1 = malloc(1);//在堆中分配了一个字节内存

//    char *p2 = malloc(10);

   

//    int *ip = malloc(sizeof(int));

//    *ip = 20;

//    printf("%d\n",*ip);//20

一些例子:

//    //练习

//    //数组:20个元素,都是int类型的。

//    //在堆区分配空间

//    //使用随机数填值。[0~30]后打印

//   

//    int *arr = malloc(sizeof(int) * 20);//在堆中分配了20int类型的内存。用arr指针来找到在堆中的位置。

//   

//    for (int i =0; i < 20; i ++) {

//        *(arr + i) = arc4random() % 30;

//    }

//   

//    for (int i = 0; i < 20 ; i ++) {

//        printf(" %d个元素:%d\n",(i+1),arr[i]);

//    }

//    //申请的内存,如果不手动释放,会一直存在。造成内存泄露。

//    //释放内存

//    free(arr);

 

free()函数:与malloc等动态分配内存的函数使用,对分配号的内存进行释放,回收内存。但是这里的释放,是标记删除。意思是对编号进行释放,但是内容仍然存在,只是告诉系统,这个内存已经可以回收,可以重新分配给其他人用。

注意:不能像下面那样写

    //切记,不能这么写,是错误的

    //原因是:先分配了6个字节,还没有释放,就去申请另外的空间,这样导致6个空间的内存不能释放。

//    int *p4 = malloc(6);

//    p4 = malloc(10);

例子:

    //练习:

//    //找出字符串中的所有数字,用malloc来存放这些数字

//    char *str = "a1b2c3d4";

//    //统计数字

//    int count = 0;

//    //循环增量

//    int i = 0;

//    //收集数字

//    char tempArr[100] = {0};

//  

//    while (*(str+i) != '\0') {

//        if (str[i] >= '0' && str[i] <='9') {

//            tempArr[count] = str[i];

//            count ++;

//        }

//        i ++;

//    }

//    //加上'\0'表示结束

//    tempArr[count] = '\0';

//    //分配空间

//    char *arr = malloc(sizeof(char) * (count+1));

//    //赋值:把栈区的数据,拷贝到堆区。

//    strcpy(arr, tempArr);

//    printf("%s\n",arr);//1234

//    //释放

//    free(arr);//释放的意思是标记删除

//   

//    printf("%s\n",arr);//仍然为1234

//   

//    arr = NULL;

//   

//    printf("%s\n",arr);//打印 (null)

 

由于free是标记删除,并不对内存里的内容进行清除,此时,还需要将我们的指针指向NULL:arr = NULL;

练习:

 

//    char *words[3] = {0};

//    for (int i = 0; i < 3; i ++) {

//        char temp[20] = {0};

//        printf("输入单词,回车结束:\n");

//        scanf("%s",temp);

//        words[i] = malloc(sizeof(char) * (strlen(temp)+1));

//        strcpy(words[i], temp);

//    }

//   

//    for (int i = 0; i < 3; i++) {

//         printf("%s\n",words[i]);

//    }

////    free(words);三个地址要逐个释放。其实words是数组名,数组名就在栈区,不能用free来释放。words[i]的值才是在堆中开辟的空间的地址。能用free释放

//    for (int i = 0 ; i < 3; i ++) {

//        free(words[i]);

//        words[i] = NULL;

//    }

 

calloc函数:与malloc差不多,只是有两个参数,第一个参数是告诉有多少个后面的类型,第二个参数是告诉有多少字节。那么全部分配下来的内存为:第一个参数 * 第二个参数。calloc在分配好内存后

    //calloc

   

//    //第一个参数:有多少个

//    //第二个参数:有多少字节

//    //全部清0

//    //使用规则和malloc分配的内存一样

//    char *p2 = calloc(10, sizeof(int));//10int类型,4字节的空间,即分配了10 * 4 = 40个字节的空间,并全部清0

//    char * p1 = calloc(10, 4);//104字节的空间,即分配了10 * 4 = 40个字节的空间,并全部清0

//   

//    for (int i = 0; i < 40 ; i ++) {

//        printf("%d",p1[i]);//0000000000000000000000000000000000000000

//    }

//    free(p1);

//    p1 = NULL;

//    free(p2);

//    p2 = NULL;

 

realloc 函数:改变一块内存。

    //realloc

   

//    char *p2 = malloc(100);

//   

//    //第一个参数:你要改变哪一块的内存

//    //第二个参数:要变成多大

//    char *p3 = realloc(p2, 120);

//   

//    free(p3);

//    p2=NULL;

//    p3 = NULL;

 

内存操作函数:

(1)、memset:设置内存给定一些内容:

 

    //memset内存设置

//    char *p3 = malloc(10);

//    //第一个参数:设置哪块内存

//    //第二个参数:设置成什么

//    //第三个参数:设置多少个字节

//    memset(p3, 2, 10);//设置p3所指向的内存,把里边的东西设置成2,设置10个字节。

//    for (int i = 0; i < 10; i ++) {

//        printf("%d",p3[i]);//2222222222

//    }

(2)、memcpy:内存拷贝函数

    //memcpy内存拷贝

//    char *p1 = malloc(10);

//    char *p2 = malloc(10);

//   

//    memset(p1, 5, 10);

//    //第一个参数:拷贝到哪

//    //第二个参数:从哪拷贝

//    //第三个参数:拷贝多少字节

//    memcpy(p2, p1, 10);//拷贝到p2,从p1拷贝过来,拷贝10个字节。

//    for (int i = 0; i < 10; i ++) {

//        printf("%d",p2[i]);//5555555555

//    }

//    free(p1);

//    p1 = NULL;

//    free(p2);

//    p2 = NULL;

(3)、memcmp:内存比较函数

    //memcmp内存比较

   

//    char *p1 = malloc(10);

//    memset(p1, 2, 10);

//   

//    char *p2 = malloc(10);

//   

//    memset(p2, 3, 10);

//    //第一个参数:第一块内存

//    //第二个参数:第二块内存

//    //第三个参数:比较多少个字节

//    //内存比较和字符串比较一样,找到第一个不相等的字节,求差值。

//    //如果所有字节逗相等,返回0

//    //返回 >0 ,第一个比第二个大,

//    //返回 <0 ,第一个比第二个小。

//    int n = memcmp(p1, p2, 10);

//    printf("%d",n);//-1

 

(5)、栈区

栈区的东西,有个特性,就是在栈内,数据是先进后出的。

在函数里定义的变量,基本上都是在栈区的,因此,一旦函数执行完毕,所有栈释放(也叫出栈),只是删除编号(地址),并没有清除数据,这时候,这些栈的使用权回归系统所有,系统可以再次分配,对里边的值重写。若是没有分配,那么在下一次遇到一个结构,类型一样的函数,里边的变量如果不给初值,那么这个变量就会使用上次出栈后遗留在栈中的数据。

#import <Foundation/Foundation.h>

 

int a(){

    int num1 = 100;

    return num1;

}

int b(){

   int num2 ;

    return num2;

}

int c(){

    int num3 ;

    return num3;

}

int main(int argc,constchar * argv[])

{ //   2015-04-08 09:36:38北京

   

//    栈区

   

   

//    int n1 = 10;

//    int n2 = 20;//

//    内存不具有清空的功能

//   

//    //每一个函数都有一个叫做栈帧的东西

//    //由于ab两个函数结构相同,使用内存情况相同,b其实使用的是a的内存,所以原来的值被使用。

//    a();

//    printf("%d\n",b());//打印100

//    //c函数使用之前,调用了printf,导致b残留的数据被覆盖,原来的值无法使用。

//    printf("%d\n",c());//打印0

//    int n3 = 30;

    return 0;

}

一个错误的例子:

#import <Foundation/Foundation.h>

////错误

//char *backStr(){//   

//    //strbackStr的栈内,一旦函数执行完毕,所有的栈内释放(也叫出栈),这时候,你的str字符数组的内存使用权回归系统,系统可以再分配。这个时候,原来的数据会被覆盖,导致无法使用。

//    char str[] = "iPhone";

//    return str ;

//}

 

int main(int argc,constchar * argv[])

{ //   char *ps = backStr();

//    printf("%s\n",ps);   

    return 0;

}

此时,应该想到,跨作用域改值的只有指针作为函数参数的时候,才能实现。所以重新定义函数:

#import <Foundation/Foundation.h>

void backString(char str[],int length){

    char s[] ="iPhone";

    if (strlen(s ) > length) {

        strcpy(str , s );

    }else{

        return;//经常用来终止函数

    }

}

 

int main(int argc,constchar * argv[])

{

    char st[20] = {0};

    backString(st,20);   

    printf("%s",st );

    return 0;

}

 


29、链表

#import <Foundation/Foundation.h>

//节点结构体

typedefstruct Node{

    int data;//数据

    structNode *next;//节点

}Node ;

 

//添加节点

void addNode(Node *n,int num){

    //临时指针

    Node *temp = n;

    while (temp->next !=NULL) {

        temp = temp->next;

    }

    temp->next =malloc(sizeof(Node));

    temp->next->data = num;

    temp->next->next =NULL;

}

 

int main(int argc,constchar * argv[])

{

 


    Node *first =malloc(sizeof(Node));

    first ->data = 0;

    first ->next =NULL;

   

    addNode(first,1);

    addNode(first,2);

    addNode(first,5);

   

    return 0;

}

 

0 0
原创粉丝点击