C语言 内存分配 地址 指针 数组 参数 实例解析

C语言 内存分配 地址 指针 数组 参数 实例解析

 void 与 void 

1 void 简介
2 void简介

 C 语言 程序内存分配

内存分区状况
内存分配方式
3 register变量
4 extern 变量
5 static变量 与 全局变量区别
堆 和 栈比较
各区分布情况

 指针与地址

与 操作
指针定义解析
指针运算及示例

 函数参数的传值调用和传址调用

传值调用 和 传址调用
高级示例

 指针 和 数组

—————————————————————–

指针简介 : 指针式保存变量地址的变量;

– 增加阅读难度 : 指针 和 goto 语句会增加程序的理解难度容易出现错误;

– ANSI C : American National Standards Institute 美国国家标准学会即标准C;

– 通用指针类型 : ANSI C中使用 void* 作为通用指针类型即指向void的指针, void 是空类型void* 是空类型指针可以指向任意类型的地址;

1. void 与 void*

 

(1) void 简介

 

void 作用 :

– 限定参数 函数没有返回值需要使用 void 声明否则默认返回 int 类型;

– 限定返回值 : 函数不接收参数使用 void 作为参数如果传入参数编译器就会报错;

 

使用void注意点 :

– void不能表示变量 : void a, 这样定义是错误的;

– 默认返回值 : C 如果没有标明返回值类型默认的返回值不是 void, 是 int 类型;

– void参数 : C 语言中参数是void, 传入参数不会出错, C++中传入参数会出错因此这里我们统一规定如果函数没有参数就定义为void;

(2) void*简介

 

void * 作用 :

– 通用数据类型 : void * 指针可以存放任意类型数据的地址任何数据类型的指针都可以赋值给 void * 通用类型指针;
– 任意类型 : 如果 函数 的 参数 和 返回值 可以是任意类型就可以使用 void * 作为函数的 参数 或者 返回值;

 

使用void* 注意点 :

– void * 与 其它类型互相赋值 : int * 变量可以赋值给 void * 变量但是void * 变量如果赋值给 int * 变量需要强转为 int * 类型;

 void * 不允许进行 算数操作 : 标准中规定 void * 类型不允许进行 加减乘除 算数运算因为我们不知道这个类型的大小, GUN void * 等价于 char * ;

2. C 语言 程序内存分配

 

(1) 内存分区状况

 

栈区 (stack) :

– 分配释放方式 : 由编译器自动分配 和 释放;

– 存放内容 : 局部变量参数;

– 特点 : 具有 后进先出 特性适合用于 保存 恢复 现场;

 

堆区 (heap) :

– 分配释放方式 : 由程序员手动 分配(malloc) 和 释放(free), 如果程序员没有释放那么程序退出的时候会自动释放;

– 存放内容 : 存放程序运行中 动态分配 内存的数据;

– 特点 : 大小不固定可能会动态的 放大 或 缩小;

 

堆区内存申请 :

– 申请过程 : OS中有一个记录空闲内存地址的链表如果程序员申请内存就会找到空间大于申请内存大小的节点将该节点从空间内存链表中删除并分配该节点;

– 剩余内存处理 : 系统会将多余的部分重新放回 空闲内存链表中;

– 首地址记录大小 : 分配内存的首地址存放该堆的大小这样释放内存的时候才能正确执行;

 

全局区/静态区 (数据段 data segment / bss segment) :

– 分配释放方式 : 编译器分配内存程序退出时系统自动释放内存;

– 存放内容 全局变量静态变量;

– 特点 : 全局变量 和 静态变量存储在一个区域初始化的两种变量 和 未初始化的 存储在不同区域但是两个区域是相邻的;

 

常量区 :

– 分配释放方式 退出程序由系统自动释放;

– 存放内容 : 常量;

 

代码区 (text segment) :

– 分配释放方式 : 编译器分配内存程序退出时系统自动释放内存;

– 存放内容 : 存放 程序的二进制代码和一些特殊常量;

 

内存存放顺序 (由上到下栈区 -> 堆区 -> 全局区 -> 常量区 -> 代码区;

 

(2) 内存分配方式

 

全局内存分配 :

– 生命周期 编译时分配内存程序退出后释放内存与 程序 的生命周期相同;

– 存储内容 : 全局变量静态变量;

 

栈内存分配 :

– 生命周期 : 函数执行时分配内存执行结束后释放内存;

– 特点 : 该分配运算由处理器处理效率高但是栈内存空间有限;

 

堆内存分配 :

– 生命周期 : 调用 malloc()开始分配调用 free()释放内存完全由程序员控制;

– 谨慎使用 : 如果分配了 没有释放会造成内存泄露如果频繁 分配 释放 会出现内存碎片;

 

(3) register变量

 

使用场景 : 如果 一个变量使用频率特别高可以将这个变量放在 CPU 的寄存器中;

– 修饰限制 : 只有 局部变量 和 参数 可以被声明为 register变量全局 和 静态的不可以;

– 数量限制 : CPU 寄存器 很宝贵不能定义太多register变量;

 

(4) extern 变量

 

extern变量概念 : 声明外部变量外部变量就是在函数的外部定义的变量在本函数中使用;

– 作用域 : 从外部变量定义的位置开始知道本源码结束都可以使用但是只能在定义extern后面使用前面的代码不能使用;

– 存放位置 : 外部变量 存放在 全局区;

 

extern变量作用 : 使用extern修饰外部变量① 扩展外部变量在本文件中的作用域② 将外部变量作用域从一个文件中扩展到工程中的其它文件;

 

extern声明外部变量的情况 :

– 单个文件内声明 : 如果不定义在文件开头其作用范围只能是 定义位置开始文件结束位置结束;

– 多个文件中声明 : 两个文件中用到一个外部变量只能定义一次编译 和 连接的时候如果没有这个外部变量系统会知道这个外部变量在别处定义将另一个文件中的外部变量扩展到本文件中;

 

extern编译原则 :

– 本文件中能找到 编译器遇到 extern 的时候现在本文件中找外部变量的定义的位置如果找到就将作用域扩展到 定义的位置 知道文件结束;

– 本文件中找不到 : 如果本文件中找不到连接其它文件找外部变量定义如果找到将外部变量作用域扩展到本文件中;

– 外部文件找不到 : 报错;

 

使用效果 : extern 使用的时候可以不带数据类型;

– 本文件 : int A = 0; 在第10, extern A 在第一行那么A的作用域就扩展为从第一行到文件末尾;

 多文件 : 在任意文件中定义了 int A = 0; 在本文件中声明 extern A, 那么从当前位置到文件末尾都可以使用该变量;

 

 

(5) static变量 与 全局变量区别

 

static 变量 与 全局变量 相同点 : 全局变量是静态存储的存储的方式 和 位置基本相同;

 

static 变量 与 全局变量不用点 : 全局变量的作用域是 整个项目工程 横跨过个文件静态变量的作用域是 当前文件其它文件中使用是无效的;

 

变量存储位置 : 全局变量 和 静态变量 存放在 全局区/静态去局部变量存放在 栈区(普通变量和 堆区(指针变量);

 

变量静态化 :

– 局部变量 : 局部变量 加上 static , 相当于将局部变量的生命周期扩大到了整个文件作用域不改变;

– 全局变量 : 全局变量 加上 static , 相当于将全局变量的作用域缩小到了单个文件生命周期是整个程序的周期;

 

关于函数头文件的引申 :

– 内部函数 : 单个文件中使用的内部函数仅在那个特定文件中定义函数即可;

– 全局函数 : 如果要在整个工程中使用一个全局函数需要将这个函数定义在一个头文件中;

 

static变量与普通变量区别 :

– static全局变量 与 全局变量区别 : static 全局变量 只初始化一次防止在其它文件中使用;

– static局部变量 与 局部变量区别 : static 局部变量 只初始化一次下一次依据上一次结果;

 

static函数与普通函数区别 : static 函数在内存中只保留一份普通函数 每调用一次就创建一个副本;

.

 

(6) 堆 和 栈比较

 

 

(heap)和栈(stack)区别 :

– 申请方式 : stack 由系统自动分配, heap 由程序员进行分配;

– 申请响应 : 如果 stack 没有足够的剩余空间就会溢出堆内存从链表中找空闲内存;

– 内存限制 : stack 内存是连续的从高位向低位扩展而且很小只有几M, 是事先定好的在文件中配置; heap 是不连续的从低位向高位扩展系统是由链表控制空闲程序链表从低地址到高地址堆大小受虚拟内存限制一般32位机器有4G heap;

– 申请效率 : stack 由系统分配效率高; heap 由程序员分配速度慢容易产生碎片;

 

(7) 各区分布情况

按照下图分布 : 由上到下顺序 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区;

验证分区状况 :

– 示例程序 :

/************************************************************************* 
    > File Name: memory.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Mon 10 Mar 2014 08:34:12 PM CST 
 ************************************************************************/  
 
#include<stdio.h>  
#include<stdlib.h>  
 
int global1 = 0, global2 = 0, global3 = 0;  
 
void function(void)  
{  
        int local4 = 0, local5 = 0, local6 = 0;  
        static int static4 = 0, static5 = 0, static6 = 0;  
        int *p2 = (int*)malloc(sizeof(int));  
 
        printf("子函数 局部变量 : \n");  
        printf("local4 : %p \n", &local4);  
        printf("local5 : %p \n", &local5);  
        printf("local6 : %p \n", &local6);  
 
        printf("子函数 指针变量 : \n");  
        printf("p2 : %p \n", p2);  
 
        printf("全局变量 : \n");  
        printf("global1 : %p \n", &global1);  
        printf("global2 : %p \n", &global2);  
        printf("global3 : %p \n", &global3);  
 
        printf("子函数 静态变量 : \n");  
        printf("static4 : %p \n", &static4);  
        printf("static5 : %p \n", &static5);  
        printf("static6 : %p \n", &static6);  
 
        printf("子函数地址 : \n");  
        printf("function : %p \n", function);  
}  
 
int main(int argc, char **argv)  
{  
        int local1 = 0, local2 = 0, local3 = 0;  
        static int static1 = 0, static2 = 0, static3 = 0;  
        int *p1 = (int*)malloc(sizeof(int));  
        const int const1 = 0;  
        char *char_p = "char";  
 
        printf("主函数 局部变量 : \n");  
        printf("local1 : %p \n", &local1);  
        printf("local2 : %p \n", &local2);  
        printf("local3 : %p \n", &local3);  
        printf("const1 : %p \n", &const1);  
 
        printf("主函数 指针变量 : \n");  
        printf("p1 : %p \n", p1);  
 
        printf("全局变量 : \n");  
        printf("global1 : %p \n", &global1);  
        printf("global2 : %p \n", &global2);  
        printf("global3 : %p \n", &global3);  
 
        printf("主函数 静态变量 : \n");  
        printf("static1 : %p \n", &static1);  
        printf("static2 : %p \n", &static2);  
        printf("static3 : %p \n", &static3);  
 
        printf("字符串常量 : \n");  
        printf("char_p : %p \n", char_p);  
 
        printf("主函数地址 : \n");  
        printf("main : %p \n", main);  
 
        printf("= = = = = = = = = = = = = = = \n");  
 
        function();  
 
        return 0;  
}

– 执行结果 :

[root@ip28 pointer]# gcc memory.c   
[root@ip28 pointer]# ./a.out   
主函数 局部变量 :   
local1 : 0x7fff75f5eedc   
local2 : 0x7fff75f5eed8   
local3 : 0x7fff75f5eed4   
const1 : 0x7fff75f5eed0   
主函数 指针变量 :   
p1 : 0x19bad010   
全局变量 :   
global1 : 0x600e14   
global2 : 0x600e18   
global3 : 0x600e1c   
主函数 静态变量 :   
static1 : 0x600e34   
static2 : 0x600e30   
static3 : 0x600e2c   
字符串常量 :   
char_p : 0x4009f7   
主函数地址 :   
main : 0x40065f   
= = = = = = = = = = = = = = =   
子函数 局部变量 :   
local4 : 0x7fff75f5eea4   
local5 : 0x7fff75f5eea0   
local6 : 0x7fff75f5ee9c   
子函数 指针变量 :   
p2 : 0x19bad030   
全局变量 :   
global1 : 0x600e14   
global2 : 0x600e18   
global3 : 0x600e1c   
子函数 静态变量 :   
static4 : 0x600e28   
static5 : 0x600e24   
static6 : 0x600e20   
子函数地址 :   
function : 0x400528

 3. 指针与地址

(1) & 与 操作

取地址运算符 & : p = &c;

– 表达式解析 : 将 的地址赋值给 变量 p, p 是指向 变量的指针;

– 可以使用的情况 : 取地址操作 只能用于内存中的对象如变量 或 数组栈内存 堆内存 都可以;

– 不适用的情况 : 不能用于 表达式常量, register类型变量;

 

间接引用运算符 : * ;

– 声明指针 : int *p ; 该表达式的含义是 *p 的结果是 int 类型声明变量 a, int a, 声明指针 *p , int *p;

– 获取指针指向的值 : int a = *p ;

 

(2) 指针定义解析

声明指针 和 函数 : int *p, max(int a, int b), 声明指针变量 语法 与声明 变量语法类似同理声明函数也一样;

– 原理 : *p 和 max()返回值 类型都是 int 类型;

指针指向 : 每个指针都必须指向某种特定类型;

– 例外 : void *p 可以指向任何类型但是 不能进行取值运算, *p 是错误的因为不知道 指向的数据类型;

 

(3) 指针运算及示例

指针相关运算 : int x = 0; int *p = &x; 那么*p 就可以代表x;

– 算数运算 : x = x + 1; 等价于 *p = *p + 1 ; int y = x + 1; 等价于 int y = *p + 1;

– 自增运算 : 前提 : ++, * 运算顺序是自右向左;  ++*p 和 (*p)++, p 指向的值自增1, 注意要加上括号否则会将地址自增;

– 指针赋值 : int *p, *q; int a = 0; p = &a; q = p; 最终结果 和 都指向了 变量 a;

示例程序 :

/************************************************************************* 
    > File Name: pointer_address.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Mon 10 Mar 2014 09:52:01 PM CST 
 ************************************************************************/  
 
#include<stdio.h>  
 
int main(int argc, char ** argv)  
{  
        int *p, *q;  
        int a = 10, b;  
 
        //p指针指向a变量  
        p = &a;  
 
        //*p 可以代替 a 进行运算  
        ++*p;  
 
        b = *p + 5;  
 
        //指针之间可以直接相互赋值  
        q = p;  
 
        //打印 p 和 q 指针指向的值  
        printf("*p = %d \n", *p);  
        printf("*q = %d \n", *q);  
 
        return 0;  
}

执行结果 :

[root@ip28 pointer]# gcc pointer_address.c   
[root@ip28 pointer]# ./a.out   
*p = 11   
*q = 11

4. 函数参数的传值调用和传址调用

 

(1) 传值调用 和 传址调用

 

传值调用 : 以传值的方式将参数传递给函数不能直接修改主函数中变量的值仅仅是将副本传递给了函数;

 

传址调用 : 将 变量的指针 传递给函数当函数对指针进行操作的时候主函数中的值也进行了对应变化;

 

交换函数示例1 :

/************************************************************************* 
    > File Name: swap.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Mon 10 Mar 2014 11:07:18 PM CST 
 ************************************************************************/  
 
#include<stdio.h>  
 
void swap_1(int a, int b)  
{  
        int temp;  
        temp = a;  
        a = b;  
        b = temp;  
 
        printf("swap_1 传值 函数 a = %d, b = %d \n", a, b);  
}  
 
void swap_2(int *a, int *b)  
{  
        int temp;  
        temp = *a;  
        *a = *b;  
        *b = temp;  
 
        printf("swap_2 传址 函数 a = %d, b = %d\n", *a, *b);  
}  
 
int main(int argc, char **argv)  
{  
        int a = 10, b = 5;  
 
        printf("初始值 : a = %d, b = %d \n\n", a, b);  
 
        swap_1(a, b);  
        printf("执行 swap_1 函数, a = %d, b = %d \n\n", a, b);  
 
        swap_2(&a, &b);  
        printf("执行 swap_2 函数, a = %d, b = %d \n", a, b);  
 
        return 0;  
}

执行结果 :

[root@ip28 pointer]# gcc swap.c   
[root@ip28 pointer]# ./a.out   
初始值 : a = 10, b = 5   
 
swap_1 传值 函数 a = 5, b = 10   
执行 swap_1 函数, a = 10, b = 5   
 
swap_2 传址 函数 a = 5, b = 10  
执行 swap_2 函数, a = 5, b = 10

示例解析  :

– 传值调用 : swap_1 是传值调用传入的是 main 函数中的 a b 两个变量的副本因此函数执行完毕后主函数中的值是不变的;

– 传址调用 : swap_2 是传址调用传入的是 a , b 两个变量的地址 &a, &b, 当在swap_2 中进行修改的时候主函数中的 a,b变量也会发生改变;

 

 

(2) 高级示例

 

需求分析 : 调用getint()函数将输入的数字字符 转为一个整型数据;

 

getch 和 ungetch 函数 :

– 使用场景 : 当进行输入的时候不能确定是否已经输入足够的字符需要读取下一个字符进行判断如果多读取了一个字符就需要将这个字符退回去;

– 使用效果 : getch() 和 ungetch() 分别是预读下一个字符和 将预读的字符退回去这样对于其它代码而言没有任何影响;

 

注意的问题 出现问题暂时编译不通过找个C语言大神解决;

代码 :

/************************************************************************* 
    > File Name: getint.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Mon 10 Mar 2014 11:40:19 PM CST 
 ************************************************************************/  
#include <stdio.h>  
#include <stdlib.h>  
#include <ctype.h>  
#define SIZE 5  
 
int getint(int *p)  
{  
    //sign 是用来控制数字的正负  
    int c, sign;  
 
    //跳过空白字符, 如果是空白字符, 就会进行下一次循环, 直到不是空白字符为止  
 
    while(isspace(c = getc(stdin)));  
 
    //如果输入的字符不是数字, 就将预读的数据退回到标准输入流中  
    if(!isdigit(c) && c != EOF && c != '+' && c != '-')  
    {  
        ungetc(c, stdin);  
        return 0;  
    }  
 
    /* 
     * 如果预读的是减号, 那么sign 标识就是 -1,  
     * 如果预读的是加号, 那么sign 标识就是 1; 
     */  
    sign = (c == '-') ? -1 : 1;  
    //如果 c 是 加号 或者 减号, 再预读一个字符&  
    if(c == '+' || c == '-')  
        c = getc(stdin);  
 
    for(*p = 0; isdigit(c); c = getc(stdin))  
        *p = 10 * *p + (c - '0');  
 
    *p *= sign;  
 
    if(c != EOF)  
        ungetc(c, stdin);  
 
    return c;  
 
}  
 
int main(int argc, char **argv)  
{  
    int n, array[SIZE], i;   
    for(n = 0; n < SIZE && getint(&array[n]) != EOF; n++);  
 
    for(i = 0; i < SIZE; i++)  
    {  
        printf("array[%d] = %d \n", i, array[i]);  
    }  
    return 0;  
}

执行结果 :

octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out   
123  
123 43  
674 1  
array[0] = 123   
array[1] = 123   
array[2] = 43   
array[3] = 674   
array[4] = 1

5. 指针 和 数组

指针数组比较 :

– 可互相替代 : 数组下标执行的操作都可以使用指针替代;

– 效率比较 : 使用指针操作效率比数组要高;

 

指针 与 数组初始化 :

– 声明数组 : int a[10]; 定义一个长度为10 int数组;

– 声明指针 : int *p; 定义一个指针该指针指向整型;

– 相互赋值 : p = &a[0], 将数组第一个元素的地址赋值给指针变量;

– 使用指针获取数组对象 : *p 等价于 a[0], *(p + 1) 等价于 a[1], *(p + i)等价于 a[i];

– 注意地址的运算 : p + i , 在地址运算上每次增加 sizeof(int) * i 个字节;

 

将数组赋值给指针的途径 :

– 将数组第一个元素地址赋值给指针变量 : p = &a[0];

– 将数组地址赋值给指针变量 : p = a;

 

指针 和 数组 访问方式互换 : 前提 int *p, a[10]; p = a;

– 数组计算方式 : 计算a[i]的时候先将数组转化为 *(a + i)指针然后计算该指针值;

– 取值等价 : a[i] 等价于 *(p + i);

– 地址等价 : &a[i] 与 a + i 是等价的;

– 指针下标访问 : p[i] 等价于 *(p + i);

– 结论 : 通过数组和下标 实现的操作 都可以使用 指针和偏移量进行等价替换;

 

指针 和 数组 的不同点 :

– 指针是变量 : int *p, a[10]; p = a 和 p++ 没有错误;

– 数组名不是变量 : int *p, a[10]; a = p 和 a++ 会报错;

 

数组参数 :

– 形参指针 : 将数组传作为参数传递给函数的时候传递的是数组的首地址传递地址形参是指针;

 

数组参数示例 :

– 函数参数是数组 : 函数传入一个字符串数组参数返回这个字符串长度;

/************************************************************************* 
    > File Name: array_param.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Sat 15 Mar 2014 12:46:57 AM CST 
 ************************************************************************/  

#include<stdio.h>  

//计算字符串长度  
int strlen(char *s)  
{  
        int n;  
        for(n = 0; *s != '\0'; s++)  
                n++;  
        return n;  
}  

int main(int argc, char** argv)  
{  
        printf("strlen(djdhaj) = %d \n", strlen("djdhaj"));  
        printf("strlen(12) = %d \n", strlen("12"));  
        printf("strlen(dfe) = %d \n", strlen("dfe"));  
}

 执行结果 : warning: conflicting types for built-in function strlen原因是 C语言中已经有了 strlen 函数了如果改一个函数名就不会有这个警告了;

[root@ip28 pointer]# gcc array_param.c   
array_param.c:12: warning: conflicting types for built-in function ‘strlen’  
[root@ip28 pointer]# ./a.out             
strlen(djdhaj) = 6   
strlen(12) = 2   
strlen(dfe) = 3

数组和指针参数 : 将数组名传给参数函数根据情况判断是作为数组还是作为指针;

– 实参 : 指针偏移量 和 数组下标 都可以作为 数组或指针函数形参如 数组情况fun(&array[2]) 或者 指针情况fun(p + 2);

– 形参 : 函数的形参可以声明为 fun(int array[]), 或者 fun(int *array), 如果传入的是数组的第二个元素的地址可以使用array[-2]来获数组取第一个元素;

数组指针参数示例 :

/************************************************************************* 
    > File Name: param_array_pointer.c 
    > Author: octopus 
    > Mail: octopus_work.163.com  
    > Created Time: Sat 15 Mar 2014 01:28:33 AM CST 
 ************************************************************************/  

#include<stdio.h>  

//使用指针做形参 取指针的前两位 和 当前位  
void fun_p(int *p)  
{  
        printf("*(p - 2) = %d \n", *(p - 2));  
        printf("*p = %d \n", *p);  
}  

//使用数组做形参 取数组的 第-2个元素 和 第0个元素  
void fun_a(int p[])  
{  
        printf("p[-2] = %d \n", p[-2]);  
        printf("p[0] = %d \n", p[0]);  
}  

int main(int argc, char **argv)  
{  
        int array[] = {1,2,3,4,5};  
        //向指针参数函数中传入指针  
        printf("fun_p(array + 2) : \n");  
        fun_p(array + 2);  

        //向数组参数函数中传入数组元素地址  
        printf("fun_a(&array[2]) : \n");  
        fun_a(&array[2]);  

        //向指针参数函数中传入数组元素地址  
        printf("fun_p(&array[2]) : \n");  
        fun_p(&array[2]);  

        //向数组参数函数中传入指针  
        printf("fun_a(array + 2) : \n");  
        fun_a(array + 2);  
        return 0;  
}

执行效果 :

[root@ip28 pointer]# gcc param_array_pointer.c   
[root@ip28 pointer]# ./a.out   
fun_p(array + 2) :   
*(p - 2) = 1   
*p = 3   
fun_a(&array[2]) :   
p[-2] = 1   
p[0] = 3   
fun_p(&array[2]) :   
*(p - 2) = 1   
*p = 3   
fun_a(array + 2) :   
p[-2] = 1   
p[0] = 3

转自:http://blog.csdn.net/shulianghan/article/details/20472269


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
大学生在线租房平台管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、报修评价管理、字典管理、房东管理、房屋管理、房屋收藏管理、房屋留言管理、房屋租赁管理、租房论坛管理、公告信息管理、留言板管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 大学生在线租房平台管理系统可以提高大学生在线租房平台信息管理问题的解决效率,优化大学生在线租房平台信息处理流程,保证大学生在线租房平台信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理大学生在线租房平台信息,包括房屋管理,培训管理,报修管理,薪资管理等,可以管理公告。 房屋管理界面,管理员在房屋管理界面中可以对界面中显示,可以对房屋信息的房屋状态进行查看,可以添加新的房屋信息等。报修管理界面,管理员在报修管理界面中查看报修种类信息,报修描述信息,新增报修信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
基于hal库的OLED显示屏驱动C语言实现源码.zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip基于hal库的OLED显示屏驱动C语言实现源码.zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值