数据结构基础铺垫

1、struct

  • C语言中的struct可以看作变量的集合

1.1 结构体与柔性数组

  • 柔性数组即数组大小待定的数组

  • C语言中可以由结构体产生柔性数组

  • C语言中结构体的最后一个元素可以是大小未知的数组

    • array[]柔性数组作为标识符,不占用内存空间
    struct SoftArray
    {
    	int len;
    	int array[];
    };
    

1.2 柔性数组应用实例

struct SoftArray
{
    int len;
    int array[];
};

struct softArray* create_soft_array(int size)
{
    struct SoftArray* ret = NULL;
    
    if(size > 0)
    {
        ret = (struct SoftArray*)malloc(sizeof(struct SoftArray) + sizeof(int) * size);
        
        ret->len = size;
    }
    
    return ret;
}

void delete_soft_array(struct SoftArray* sa)
{
    free(sa);
}

void func(struct SoftArray* sa)
{
    int i = 0;
    
    if( NULL != sa )
    {
        for(i = 0; i < sa->len; i++)
        {
            sa->array[i] = i + 1;
        }
    }
}

int main()
{
    int i = 0;
    struct SoftArray* sa = creat_soft_array(10);
    
    func(sa);
    
    for(i = 0; i < sa->len; i++)
    {
        printf("%d\n", sa->array[i]);
    }
    
    delete_soft_array(sa);
    
    return 0;
}

2、union

  • C语言中的union在语法上与struct相似

  • union只分配最大成员的空间,所有成员共享这个空间

    struct A
    {
    	int a;
    	int b;
    	int c;
    };
    
    union B
    {
    	int a;
    	int b;
    	int c;
    };
    
    int main()
    {
    	printf("%d\n", sizeof(struct A));//12
    	printf("%d\n", sizeof(union B));//4
    	
    	return 0;
    }
    
  • union的使用受系统大小端的影响

    • 小端模式低地址存储低位数据
    • 大端模式低地址存储高位数据

2.1 利用union的性质判断系统大小端

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MkHldrKR-1690886743255)(C:\Users\无实的谎言花\Desktop\上海\struct 和 union\大小端判断.png)]

int system_mode()
{
	union SM
	{
		int i;
		char c;
	};
	
	union SM sm;
	sm.i = 1;
	
	return sm.c;
}

int main()
{
	printf("System Mode: %d\n", system_mode());
    //返回1为小端,返回0为大端
	return 0;
}

3、函数类型

  • C语言中的函数有自己特定的类型
  • 函数的类型由返回值参数类型参数个数共同决定
    • int add(int i, int j)的类型为int(int, int)
  • C语言中通过typedef为函数类型重命名
    • typedef type name(parameter list)
    • 例:typedef int f(int,int);
    • typedef void p(int);
  • 值传递:普通变量作为函数参数传递是单向的值传递,只是将实参的值复制一份给形参,形参的改变不会影响实参的值,因为所在内存空间不同,如果传递的是地址,被调函数使用指针接收,如果在被调函数中,没有更改指针指向空间中的内容,只改变指向,不改变内容
  • 地址传递:指针、数组名作为函数参数传递,是地址传递,需要在被调函数中更改指针指向空间的内容,形参内容的改变,实参内容也随之改变
  • 值返回:普通变量通过函数返回值进行返回是单向的值返回,在主函数的调用中,只能作为右值使用,不能重新赋值
  • 地址返回:需要返回生命周期比较长的变量地址(全局变量、静态局部变量、堆区空间地址、只掉函数地址传递的空间),该函数的返回值是一个左值,可以直接使用,也可以重新赋值,重新赋值后,被调函数中的变量也随之改变

4、malloc 和 free

  • malloc所分配的是一块连续的内存
  • malloc以字节为单位,且不带任何的类型信息
  • free用于将动态内存归还系统
    • void* malloc(size_t size);
    • void free(void* pointer);

4.1 注意点

  • malloc 和 free是库函数,而不是系统调用
  • malloc实际分配的内存可能会比请求的多
  • 不能依赖于不同平台下的malloc行为
  • 当请求的动态内存无法满足时malloc返回NULL
  • 当free的参数为NULL时,函数直接返回

5、calloc 和 realloc

  • malloc的同胞兄弟
    • void* calloc(size_t num, size_t size);
    • void* realloc(void* pointer, size_t new_size);
  • calloc的参数代表所返回内存的类型信息
    • calloc会将返回的内存初始化为0
  • realloc用于修改一个原先一绝分配的内存块大小
    • 在使用realloc之后应该使用其返回值
    • 当pointer的第一个参数为NULL时,等价于malloc

6、typedef

  • typedef用于给一个已经存在的数据类型重命名
  • typedef本质上不能产生新的类型
  • typedef重命名的类型
    • 可以在typedef语句之后定义
    • 不能被unsignedsigned修饰
    • 语法typedef type new_name;

7、进程在内存中的分配

在这里插入图片描述

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
#include <unistd.h>

static int g_init = 255;
static float g_uninit;

static void text()
{
    
}

int main(int argc, const char *argv[])
{
    static double s_init = 0.255;
    static double s_uninit;
    int i = 0;
    int* p = malloc(4);
    
    printf("argv[0] = %p\n", argv[0]);
    printf("&i = %p\n", &i);
    printf("p = %p\n", p);
    printf("&g_uninit = %p\n", &g_uninit);
    printf("&s_uninit = %p\n", &s_uninit);
    printf("&g_init = %p\n", &g_init);
    printf("&s_init = %p\n", &s_init);
    printf("text = %p\n", text);
    
    free(p);
    
    return 0;
}

/*输出结果
argv[0] = 0x7fff3ff00192	进程入口
&i = 0x7fff3feffb6c			栈区
p = 0x558eb65b9260			堆区
&g_uninit = 0x558eb54f2028	.bass区
&s_uninit = 0x558eb54f2030	.bass区
&g_init = 0x558eb54f2010	.data区
&s_init = 0x558eb54f2018	.data区
text = 0x558eb52f173a		代码段区
*/

8、内存分区

  • 一个进程启动后,系统会为该进程分配4G的虚拟内存
  • 0-3G是用户空间,程序员写代码操作部分
  • 3-4G是内核空间,主要与底层驱动打交道
  • 所有进程会共享3-4G的内核空间,但每个进程独立拥有0-3G的用户空间
  • 0-3G用户空间又被分为三个部分:栈区、堆区、静态区(全局区)
  • 全局区又分为四个段:.bss段、.data段、.ro段、.txt段
  • 应用层主要操作0-3G的用户空间,底层主要操作3-4G的内核空间

8.1 程序中的栈

  • 栈是现代计算机程序里最为重要的概念之一
  • 栈在程序中用于维护函数调用上下文
  • 函数中的参数和局部变量存储在栈上
  • 栈保存了一个函数调用所需的维护信息
    • 参数
    • 返回地址
    • 局部变量
    • 调用上下文
  • 函数调用时,对应的栈空间在函数返回前是专用的
  • 函数调用结束后,栈空间将被释放,数据不再有效

8.2 程序中的堆

  • 堆是程序中一块预留的内存空间,可由程序自由使用
  • 堆中被程序申请使用的内存在被主动稀释前将一直有效
  • C语言程序中通过库函数的调用获得堆空间
    • 头文件:malloc.h
    • malloc 以字节的方式动态申请堆空间
    • free将堆空间归还给系统

8.3 程序中的静态存储区

  • 静态存储区随着程序的运行而分配空间
  • 静态存储区的生命周期直到程序运行结束
  • 在程序的编译器静态存储区的大小就已经确定了
  • 静态存储区主要用于保存全局变量静态局部变量
  • 静态存储区的信息最终会保存到可执行程序中

小结

  • 栈,堆和静态存储区是程序中的三个基本数据区
    • 栈区主要用于函数调用的使用
    • 堆区主要是用于内存的动态申请和归还
    • 静态存储区用于保存全局变量和静态变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值