C语言-DynamicMemory

//  main.m

#import <Foundation/Foundation.h>

#import "Student.h"

void test(){
    int a = 10;
    printf("test 中a 的地址%p\n",&a);
}
void test1(){
    int b = 20;
    printf("test1中的 b 的地址%p\n",&b );
}


char * str()
{
    char string[20] = "iPhone";
    return string;  //内存问题一:野指针问题,空间回收,访问不该访问的内存;
}





int main(int argc, const char * argv[])
{

    //定义5个学生数组
    
//    Student BJS[5] = {0};
//    printf("请输入5个学生的姓名,性别,年龄,学号,分数:\n");
//    
//    for (int i = 0; i < 5; i++) {
//        scanf("%s%c%d %d %f",(BJS + i)->name,&(BJS + i)->sex,&(BJS + i)->age,&(BJS + i)->num,&(BJS + i)->score);
//    }
//    
//    printStudent(BJS,5);
//    
//    sortStudentByName(BJS,5);
//    
//    printStudent(BJS,5);
//    
//    
    
    printf("=====================栈区======================\n");
    int a = 10;
    int b = 10;
    int c = 10;
    printf("%p\n%p\n%p\n",&a,&b,&c);
    //栈区    局部变量存储的区域
    /*
     1.栈区内存分配规则:由大到小分配,由小到大存储;
     2.函数调用就是一个入栈出栈的过程,调用函数,入栈,系统会为函数分配所需要的空间;函数结束,出栈,系统回收函数使用的内存空间;
     3.栈区空间的分配有系统完成,不需要我们(iOS 开发工程师)手动管理;
     4.系统为每一个应用程序分配的栈区空间有限且小,但是程序之所以没有崩溃,是因为栈区空间一直频繁的开辟和释放;
     
     */
    
//    int a[5] = {1,2,4,5,6};
//    for (int i = 0 ; i < 5; i++) {
//        printf("a地址:%p\n",(a + i));
//    }
//    int b[5] = {3,4,6,7,9};
//    for (int i = 0 ; i < 5; i++) {
//        printf("b地址:%p\n",(b + i));
//    }

    test();
    test1();           //a 和 b 的地址是相同的, a 被调用完成后直接释放, b又用得那个地址,假如 b 不初始化的话将会得到之前这个空间内存储的值,即之前a 的值.栈内存返回是不安全的,禁止!!!
    
    printf("=====================堆区======================\n");
    int *p_1 = malloc(4);
    int *p_2 = malloc(4);
    int *p_3 = malloc(4);
    printf("%p\n%p\n%p\n",p_1,p_2,p_3);
    
    
    
    
    //堆区       堆区由我们(iOS 开发工程师)手动开辟,手动释放,自主管理
    /*
     void * malloc(size_t);在堆区开辟指定字节的空间,并把对应空间的首地址返回
     void * 泛指,指代所有指针类型
     
     1.整型:在堆区开辟4个字节,并把10存储在开辟的空间内
     int *p_int = malloc(4);
     *p_int = 10;
     printf("%p  %d",p_int, *p_int);
     
     释放   void free(void *);将给定的地址空间释放
     释放的不是内容,而是内存使用的标记
     free(p_int);
     2.数组 
     //随机20-40之间的5个数,并把数字存在堆区
     int *p_ints = malloc(5 * sizeof(int));
     for(int i = 0; i < 5; i++){
     *(p_ints + i) = arc4random()%(40 - 20 + 1) + 20;
     }
     for(int i = 0; i < 5, i++){
     print("%d ",*(p_ints + i));
     }
     
     //释放  
     free(p_ints);
过度释放:     //free(p_int);  如果释放时错写为上次释放过的堆区地址,将会出现过度释放的问题;
     //如果在堆区空间释放后,继续访问此空间的话,照样会读取里面的内容,虽然其已经释放但是其空间的内容不会消失,而只是标记为已释放;该野指针的问题解决需要改变其指针为 NULL
     p_int = NULL;
     p_ints = NULL;
     
     //字符串
     char str[] = "iPhone10";
     //在堆区开辟对应空间
     char *p_str = malloc(strlen(str) + 1);
     strcpy(p_str,str);
     printf(" %s \n",p_str);
     free(p_str);
     p_str = NULL;
     
内存泄露:对于在堆区开辟的地址,没有释放,而重新定义其指向另外开辟的空间,将不会有指针指向它,它的地址无从可知了则之前的空间将会浪费,就是所谓的内存泄露.当没有释放的空间积累到一定量的时候,会造成电脑顿卡,频频 crash;所以当堆区开辟的内存使用完毕后,一定要释放!!!
     
     */
    
    //有一字符串,其中包含数字,提取其中的数字.要求动态分配内存保存
//     char str[] = "asdt43668hgkfi34";
//     //计数器
//     int count = 0;
//     //循环遍历数组  找到数字
//     for (int i = 0; i < strlen(str);i++ ){
//         if(str[i] <='9'&& str[i]>= '0'){
//     count++;
//       }
//     }
//    printf("%d ",count);
//     //根据字符数开辟空间大小
//     char *p_str = malloc( count + 1);
//     int index = 0;
//     for(int i = 0; i < strlen(str); i++){
//     if(str[i] <='9'&& str[i]>='0'){
//        *(p_str + index) = str[i];
//     index++;
//         *(p_str + index) = '\0';
//      }
//     }
//    
//   printf("  %s  ",p_str);
//
//    free(p_str);
//     p_str = NULL;
    
//    
//    //输入3个单词,动态分配内存保存学员姓名,并在最后输出
//    char str[100] = {0};
//    char *p_str[3] = {0};
//    printf("please import three words:\n");
//    for (int i = 0; i < 3; i++) {
//        //输入单词
//        scanf("%s",str);
//        //根据输入字符串的长度,开辟对应空间大小
//        p_str[i] = malloc(strlen(str + 1));
//        //将字符串拷贝到开辟空间中
//        strcpy(p_str[i],str);
//    }
//    for (int i = 0; i < 3; i++) {
//        printf("%s ",p_str[i]);
//        free(p_str[i]);
//       p_str[i] = NULL;
//    }
//    
//    
//    
    
    
    
    
    //void *calloc(int n,int size_t);开辟 n * size_t个字节空间,并把首地址返回,相比 malloc, 它多了一步清零操作,效率低;
    //存储5个整型数
//    int *p_int = calloc(5, sizeof(int));
//    for (int i = 0; i < 5; i++) {
//        printf("%d ",*(p_int + i));    //  此时打印出是5个0,因为其开辟时做了清零操作
//    *(p_int + i )  = arc4random()%(40 - 20 + 1 ) + 20;
//    }
//    for (int i = 0; i < 5; i++) {
//        printf("  %d  ",*(p_int + i));
//    }
//    free(p_int);
//    p_int = NULL;
//    
//    
//    
    
    
    
//    // void *realloc(void * p,size_t),在给定的地址基础上重新开辟新的空间,并把新的空间地址返回.
//   // 如果在之前的地址后空间被占有,且需要开辟的空间比之前要大,则系统自动换有足够空间的地址开辟.
//    char *p = malloc(20);
//    char *p_1 = realloc(p, 40);
//    
//    printf("p = %p,p_1 = %p",p,p_1);
//    
//    //free(p) //对于 realloc 来说,在释放空间时,只需要释放最新的地址,释放旧的地址就会造成过度释放;
//    
    
//    
//    //内存操作函数
//    //void *memset(void * ,int , size_t)  从传入地址开始,开辟 size_t 个字节,重置为指定数值
//    //整型
//    int *p = malloc(4);
//    memset(p,0,4);
//    printf("%d ",*p);
//    
//
//    //字符串
//    char *p_str = malloc(10);
//    memset(p_str, 'a', 9);
//    *(p_str + 9) = '0';
//    printf("%s",p_str);
//    
//    
//    //void *memcpy(void *,const void *,size_t):从指定的地址开始向目标地址拷贝指定字节的内容
//    
//    char wrongName[] = "BJS123456";
//    char rightName[] = "654321";
//    
//    //将 right 中的某个字符开始向 wrong 中的某些字符 复制3个字节
//    memcpy( wrongName+6, rightName+3, 3);
//    
//    printf("\n%s",wrongName);
//    
//    
//    
//    //memcmp(const void *, const void *,size_t):通过给定的地址和目标地址进行给定字节数的比较,前面减后面的
//
//    int result = memcmp(wrongName + 3, rightName + 1, 2);
//    printf("result = %d",result);
//    
    
    
    
    
    
//定义两个整型指针,分别⽤用malloc、calloc对其分配空间保存3个元 素,malloc分配的空间⽤用memset清零,随机对数组进⾏行赋值随机范 围1-3,赋值后⽤用memcmp⽐比较两个数组。如果相同打印Good!否则 打印Failed...
    
//    int *p_2 = calloc(3, sizeof(int));
//    int *p_1 = malloc(3 * sizeof(int));
//    memset(p_1, 0, 12);
//    for (int i = 0; i < 3; i++) {
//        *(p_1 + i) = arc4random()%(3 - 1 + 1) + 1;
//        *(p_2 + i) = arc4random()%(3 - 1 + 1) + 1;
//    }
//    
//    //比较
//    int result = memcmp(p_1, p_2, 12);
//    
//    if (result) {
//        printf("Failed!");
//    }else{
//        printf("GOOD!");
//    }
//    
//    
//    
//    
//    
    
       

    printf("\n=====================静态区======================\n");
    static int z = 10;
    static int y = 20;
    static int x = 30;
    printf("%p\n%p\n%p\n",&z,&y,&x);
    
    
    //静态区(全局区)   静态变量和全局变量存储的区域
    /* 
     //该内存区分为两个部分,一部分存储已经赋初值的静态变量和全局变量,一部分存储没有赋初值的静态变量和全局变量
     //静态变量:全局静态变量和局部静态变量;
        static int a = 10;   //用 static 修饰的变量就是静态变量
     1.静态变量如果不赋初值,则默认初值为0;
     2.静态变量只能被初始化一次;
     3.存在于程序的运行的整个过程,程序结束才释放;
     
     
     */
    

    printf("=====================常量区======================\n");
    
    
    printf("%p\n%p\n",&"d",&"er");
    
    
    
    
    
    printf("=====================代码区======================\n");
    
    printf("%p\n%p\n",test,test1);     //test为函数名,代表该函数的地址;
 

    return 0;
}


//  Student.h/Student.m

<.h>
#import <Foundation/Foundation.h>

typedef struct student  {
    char name[20];
    char sex;
    int age;
    int num;
    float score;
}Student;

//打印学生信息
void printStudent(Student *stu,int count);

//按姓名排序
void sortStudentByName(Student *stu,int count);


<.m>
#import "Student.h"


//打印学生信息
void printStudent(Student *stu,int count){
    for (int i = 0; i < count; i ++) {
        printf("name:%s,sex:%c,age:%d,num:%d,score:%.2f\n",(stu + i)->name,(stu + i)->sex,(stu + i)->age,(stu + i)->num,(stu + i)->score);
    }
}


//按姓名排序
void sortStudentByName(Student *stu,int count){
    
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - i - 1; j++) {
            if (strcmp((stu + j)->name, (stu  + j + 1)->name) > 0) {
                Student temp = *(stu + j);
                *(stu + j ) = *(stu + j + 1);
                *(stu + j + 1) = temp;
            }
        }
    }
}





你可能感兴趣的:(堆区,栈区,分配内存,动态内存分配,内存划分)