C语言数组传参的致命误区,99%的人都没意识到的指针退化问题

C++中char*传参的陷阱与最佳实践:从指针本质到内存安全 在C++编程中,指针是理解内存模型和函数调用的核心概念之一。指针本质上存储的是内存地址,当作为参数传递时,采用的是值传递机制,即传递的是地址值的副本而非指针本身。这一原理决定了函数内部可以通过地址修改指向的数据,但无法直接改变调用者指针的指向。理解这一机制对于编写健壮、可维护的代码至关重要,尤其是在涉及字符串处理、网络通信或与C语言库交互的场景中。通过辨析传值与传地址的区别,开发者可以避免常见的悬垂指针和内存泄漏问题,并设计出更安全的接口。现代C++实践中,推荐使用std::string和std::stri 阅读详情

第一章:C语言数组传参的致命误区,99%的人都没意识到的指针退化问题

在C语言中,数组作为函数参数传递时,常被开发者误认为是“按值传递”整个数组,实则不然。当数组名作为参数传入函数时,它会自动退化为指向其首元素的指针,这一现象称为“指针退化”。这意味着你无法在函数内部通过 sizeof 获取原始数组长度,极易导致越界访问或逻辑错误。

指针退化的典型表现

例如以下代码:
#include <stdio.h>

void printArray(int arr[]) {
    printf("函数内 sizeof(arr): %zu\n", sizeof(arr)); // 输出指针大小,而非数组总大小
}

int main() {
    int data[5] = {1, 2, 3, 4, 5};
    printf("main 中 sizeof(data): %zu\n", sizeof(data)); // 正确输出 20 (假设 int 为 4 字节)
    printArray(data);
    return 0;
}
尽管形参写作 int arr[],编译器实际将其视为 int *arr。因此在 printArray 中,sizeof(arr) 返回的是指针的大小(如 8 字节),而非整个数组所占空间。

避免陷阱的正确做法

为确保安全使用数组参数,应始终配合传递数组长度:
  • 显式传入数组长度作为额外参数
  • 使用固定大小的声明(如 int arr[10])仅作文档提示,不改变退化行为
  • 优先考虑封装结构体携带数组与长度信息
场景推荐方式
动态大小数组传指针 + 长度参数
固定大小数组注释说明或使用 typedef
理解并主动应对指针退化,是编写健壮C语言程序的关键一步。

第二章:深入理解数组名与指针的关系

2.1 数组名在表达式中的隐式转换机制

在C语言中,数组名在大多数表达式中会自动转换为指向其首元素的指针,这一特性称为“数组名的退化”。
隐式转换的基本规则
当数组名出现在表达式中(如算术运算、赋值、函数调用)时,除非是 sizeof、& 或字符串字面量初始化等特殊情况,否则它将被替换为指向第一个元素的指针。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;        // 等价于 &arr[0]
printf("%d", *p);    // 输出 1
上述代码中,arr 在赋值给 p 时隐式转换为 &arr[0],类型从 int[5] 变为 int*。
例外情况
  • sizeof(arr):返回整个数组的字节大小,而非指针大小;
  • &arr:取数组地址,类型为 int(*)[5],不同于 int*;
  • 作为字符串字面量用于初始化:char s[] = "hello";。

2.2 数组名作为函数参数时的退化本质

在C语言中,数组名作为函数参数传递时会“退化”为指向其首元素的指针。这意味着无论形参如何声明,实际传递的只是一个地址值。
退化行为的代码体现

void processArray(int arr[], int size) {
    printf("sizeof(arr) = %zu\n", sizeof(arr)); // 输出指针大小,而非数组总大小
}
int main() {
    int data[10];
    printf("sizeof(data) = %zu\n", sizeof(data)); // 输出 40(假设int为4字节)
    processArray(data, 10);
    return 0;
}
上述代码中,data 在主函数中为完整数组,但在 processArray 中 arr 已退化为指针,sizeof(arr) 返回指针大小(通常8字节),而非数组总大小。
退化的技术含义
  • 数组退化为指针是C语言设计的历史遗留机制,提升效率但牺牲类型信息;
  • 函数无法通过参数数组直接获取其长度,必须额外传入size参数;
  • 该机制适用于所有维度数组,多维数组仅第一维退化。

2.3 sizeof与strlen在退化后的行为差异

当数组作为参数传递给函数时,会发生“退化”,即数组名退化为指向其首元素的指针。此时,sizeof 和 strlen 的行为表现出显著差异。
sizeof 的表现
void func(char arr[10]) {
    printf("sizeof(arr) = %zu\n", sizeof(arr)); // 输出指针大小(如8字节)
}
在64位系统中,sizeof(arr) 返回指针大小而非数组总字节数,因为 arr 已退化为 char*。
strlen 的表现
  • strlen 始终计算字符串实际字符数(不包括 '\0')
  • 依赖内存中的实际内容,不受退化影响逻辑语义
行为对比表
函数退化前 (局部数组)退化后 (形参)
sizeof返回总字节数(如10)返回指针大小(如8)
strlen返回有效字符数仍返回有效字符数

2.4 通过汇编视角观察参数传递过程

在底层执行中,函数调用的参数传递依赖于寄存器与栈的协同工作。以x86-64架构为例,前六个整型参数依次使用`%rdi`、`%rsi`、`%rdx`、`%rcx`、`%r8`和`%r9`寄存器传递。
寄存器参数映射示例

movl    %edi, -4(%rbp)    # 将第一个参数(%rdi)保存到栈中
movl    %esi, -8(%rbp)    # 第二个参数(%rsi)
上述汇编指令展示了如何将寄存器中的参数值存入局部栈空间,便于函数内部访问。
参数传递规则总结
  • 整型和指针参数优先使用寄存器传递
  • 超过六个参数时,第七个及以后通过栈传递
  • 浮点参数使用XMM寄存器(如%xmm0 ~ %xmm7)
该机制显著提升了调用性能,避免频繁内存访问。

2.5 实验验证:数组与指针在传参中的等价性

在C语言中,数组名作为函数参数时会退化为指向其首元素的指针。这一特性使得数组与指针在传参场景下表现出等价性。
代码实现与对比

#include <stdio.h>

void printArray(int arr[], int size) {
    for (int i = 0; i < size; ++i)
        printf("%d ", arr[i]);
}

void printPointer(int *ptr, int size) {
    for (int i = 0; i < size; ++i)
        printf("%d ", ptr[i]);
}
两个函数分别以数组和指针形式接收参数,实际编译后具有相同的函数签名,证明其等价性。
内存布局分析
  • 数组名传递的是首元素地址
  • 形参中的arr[]被编译器解释为int*
  • 均可通过指针算术访问元素

第三章:常见错误模式与陷阱分析

3.1 误用sizeof计算退化指针的数组长度

在C/C++中,数组作为函数参数传递时会退化为指针,导致sizeof无法正确获取原始数组长度。
常见错误示例
void printSize(int arr[]) {
    printf("Size: %lu\n", sizeof(arr)); // 输出指针大小,而非数组大小
}

int main() {
    int data[] = {1, 2, 3, 4, 5};
    printf("Actual size: %lu\n", sizeof(data)); // 正确输出20(假设int为4字节)
    printSize(data); // 错误:通常输出8(64位系统指针大小)
    return 0;
}
上述代码中,arr在函数内是指针类型,sizeof(arr)返回的是指针的大小,而非原始数组元素总字节数。
解决方案对比
方法说明
显式传参长度最常用且安全的方式,配合size_t len参数
模板推导(C++)利用模板保留数组维度信息

3.2 多维数组传参时的维度丢失问题

在Go语言中,多维数组作为函数参数传递时,往往会出现维度信息丢失的问题。这是因为Go将数组按值传递,且必须显式指定除第一维外的所有维度大小。
问题示例
func processMatrix(matrix [][3]int) {
    fmt.Println("处理二维数组")
}
上述代码中,[][3]int表示一个切片,其元素是长度为3的数组。若传入[2][4]int类型数组,则无法匹配,因为第二维长度不同。
解决方案对比
方法说明
使用切片代替数组灵活但失去编译期长度检查
封装结构体保留维度信息,增强可读性

3.3 混淆固定大小数组与动态内存块

在C/C++开发中,开发者常误将固定大小数组与动态分配的内存块等同处理。虽然二者均可通过指针访问元素,但其内存属性和生命周期管理机制截然不同。
内存布局差异
固定数组在栈上分配,大小在编译期确定;而动态内存块通过 malloc 或 new 在堆上创建,运行时决定大小。

int fixedArr[10];           // 栈上分配,自动回收
int *dynamicArr = (int*)malloc(10 * sizeof(int)); // 堆上分配,需手动释放
上述代码中,fixedArr 的生命周期受限于作用域,而 dynamicArr 必须显式调用 free(dynamicArr) 释放,否则导致内存泄漏。
常见错误场景
  • 对数组名使用 free(),引发运行时崩溃
  • 误用 sizeof 计算动态内存大小,得到指针长度而非实际容量
正确区分二者有助于避免内存管理错误,提升程序稳定性。

第四章:安全高效的数组传参实践方案

4.1 显式传递数组长度以规避信息丢失

在低级语言如C中,数组作为指针传递时会丢失其长度信息,导致边界访问错误。为确保安全,应显式传递数组长度。
为何需要显式传递长度
当数组退化为指针时,sizeof无法获取原始元素个数,易引发缓冲区溢出。
代码实现示例

void processArray(int* arr, size_t len) {
    for (size_t i = 0; i < len; ++i) {
        // 安全访问:使用传入的长度控制循环
        arr[i] *= 2;
    }
}
该函数通过外部传入len参数明确数组大小,避免越界操作。
最佳实践建议
  • 始终在接口设计中包含长度参数
  • 结合断言检查长度有效性:assert(arr != NULL && len > 0);

4.2 利用封装结构体携带数组元信息

在Go语言中,原始数组类型不包含长度或容量的动态信息,限制了其在通用场景中的使用。通过将数组与相关元数据封装进结构体,可实现对数组的增强管理。
结构体封装示例
type ArrayMeta struct {
    Data   [10]int // 固定长度数组
    Length int     // 当前有效元素个数
    Max    int     // 最大可容纳数量(常量)
}
该结构体将数组本身与当前长度、最大容量等元信息绑定,便于函数间传递上下文。
优势分析
  • 封装性:隐藏数组操作细节,提供统一访问接口
  • 安全性:通过Length字段控制边界,避免越界访问
  • 可扩展性:易于添加校验和状态标记字段

4.3 使用变长数组(VLA)提升灵活性

在C99标准中引入的变长数组(Variable Length Array, VLA),允许在运行时动态确定数组大小,显著提升了程序的灵活性与内存使用效率。
VLA的基本用法

#include <stdio.h>

void process_array(int n) {
    int arr[n]; // 声明变长数组
    for (int i = 0; i < n; ++i) {
        arr[i] = i * 2;
    }
    printf("arr[5] = %d\n", arr[5]);
}

int main() {
    int size = 10;
    process_array(size);
    return 0;
}
上述代码中,arr[n] 的大小由运行时传入的 n 决定。该特性避免了静态数组的大小限制,同时简化了堆内存的手动管理。
VLA的优势与注意事项
  • 无需调用 malloc/free,简化资源管理;
  • 适用于栈空间充足且尺寸在运行时确定的场景;
  • 注意栈溢出风险,大尺寸数组建议仍使用堆分配。

4.4 函数接口设计的最佳实践与代码规范

明确职责与单一功能原则
函数应遵循单一职责原则,每个函数只完成一个明确任务。这有助于提升可读性、测试性和复用性。
参数设计规范
避免过多参数,建议使用配置对象封装可选参数:

function fetchData(url, { timeout = 5000, retries = 3, headers = {} } = {}) {
  // 实现网络请求逻辑
}
该示例通过解构赋值提供默认值,调用时只需传入必要参数,增强可维护性。
统一返回结构
为提升调用方处理一致性,推荐统一返回格式:
字段类型说明
successboolean操作是否成功
dataany成功时的数据
errorstring失败时的错误信息

第五章:结语——从误解到精通的跃迁之路

认知重构:走出初学者陷阱
许多开发者在学习并发编程时,误以为 goroutine 越多性能越好。真实案例中,某金融系统因每请求启动新 goroutine 导致调度开销激增,最终通过引入 worker pool 模式优化:

func NewWorkerPool(n int) *WorkerPool {
    pool := &WorkerPool{
        jobs:   make(chan Job, 100),
        workers: make(chan struct{}, n),
    }
    for i := 0; i < n; i++ {
        go pool.worker()
    }
    return pool
}
工程实践中的模式演进
从简单的并发执行到构建可维护的异步系统,需经历多个阶段。以下是典型成长路径:
  • 第一阶段:使用 go func() 快速实现并发
  • 第二阶段:引入 channel 控制数据流与同步
  • 第三阶段:采用 context 控制生命周期与取消传播
  • 第四阶段:结合 errgroup 实现错误聚合与协作取消
  • 第五阶段:设计可复用的并发组件,如限流器、批处理器
性能调优的真实反馈环
某电商平台在大促压测中发现 P99 延迟突增。通过 pprof 分析定位到频繁的 mutex 竞争。解决方案如下表:
问题现象根因分析解决方案
高并发写入计数器延迟升高sync.Mutex 成为瓶颈替换为 atomic.AddInt64
goroutine 泄露未关闭 channel 导致 receiver 阻塞使用 context.WithCancel 显式控制
初始并发 资源竞争 模式优化 系统稳定
C++模板与STL:从泛型编程到工程实践的核心指南 泛型编程是C++支持大规模软件工程的核心范式,它通过编写与类型无关的通用代码来解决代码复用问题。其原理基于模板元编程,编译器在编译时根据具体类型生成特化代码,实现了静态多态。这一技术的核心价值在于提升开发效率、保证类型安全并优化性能,是构建可复用、高性能库的基础。在实际应用场景中,标准模板库(STL)作为泛型编程最成功的实践,提供了经过千锤百炼的通用容器(如vector、map)和算法(如sort、find)。这些组件通过迭代器解耦,实现了数据结构和算法的独立演化,广泛应用于系统软件、游戏引擎、高频交易等对 阅读详情

相关推荐

YOLO26算法车道线检测+训练好的模型+360张数据集+pyqt可视化界面.zip

附训练好的 YOLO 权重与 PyQt 可视化检测界面,页面底部含可视化效果预览,毕设/课设开箱即用。 【数据集概况】 · 检测类别(中文):[未获取()] 【训练曲线与评估图】 【模型训练配置】 参数 | 值 模型 | yolo26n 训练轮数 | 100 epochs 输入尺寸 | 640x640 批次大小 | 24 优化器 | auto 初始学习率 | 0.01 训练设备 【关键指标汇总】 训练了 55 个 epoch,最终轮指标: 指标 | 数值 mAP50 | **0.9512** mAP50-95 | 0.6746 Precision | 0.8796 Recall | 0.8825 train/box_loss | 0.8608 train/cls_loss | 0.7232 val/box_loss | 0.9955 val/cls_loss | 0.5511 【训练过程分析】 这轮训练我经历了从初始到稳定的曲折过程。前 20 个epoch,loss 曲线呈现了陡峭的下降趋势,mAP50 指标从 0.8 开始逐步攀升,仿佛在寻找一个合适的平衡点。然而,从第 21 个epoch 开始,mAP50 的提升速率显著放缓,整体曲线显得有些曲折,有时甚至停滞不前,让我一度以为训练出现了问题。直到第 35 个epoch,loss 开始逐渐趋于平稳,这标志着模型已经找到了一个较好的收敛区间。到了最后的 20 个 epoch,尽管 mAP50 依旧在稳步上升,但提升幅度已经不大,这意味着模型已经接近其性能天花板。 在这个过程中,我重点关注了 box_loss 和 cls_loss 的变化。初期阶段,box_loss 快速下降,从 0.9 逐渐降至 0.86,而 cls_loss 则从 0.75 逐步下降至... 使用场景:毕业设计、课程设计、深度学习入门、工业场景落地验证。

【C 语言】数组 ( 一维数组形参退化 | 二维数组形参退化 | 函数形参等价关系 )

一、一维数组形参退化、 二、二维数组形参退化、 三、数组形参等价关系、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 1720

关于AI开发方法论-以文档为索引的高质量协作开发:让一次现象描述精准命中几个代码块

对AI的编码规范进行约束

为什么C语言中的数组参数会退化为指针?

Make a little progress every day.

ABCisCOOL的博客 1171

Visual Tracker Benchamark傻瓜式教程(二)

问题  1 1  在调用main.m跑TRE和SRE时,因为会生成相应的.mat数据文件,如果跑完以后发现自己算法生成的.mat文件有问题,那么要把该文件删除,待找到错误原因后,重新生成相应的.mat文件。因为程序中写的是如果已经存在了.mat文件,例如已经存在car4_STC.mat文件,即使该文件中的数据有错误,但是重新跑时会默认该文件中的数据写完,不会重新写入数据 问题  2  b

mingbujingren的专栏 9928

VSCODE编辑+EIDE插件调试+STM8_Debug插件调试+IAR_STM8工具链编译开发项目

1. 安装 在VS CODE安装EIDE、STM8-Debug插件 2. 使用 EIDE 创建一个 8/16 Bit MCU 项目 新建虚拟文件夹,把工程外部的文件添加进虚拟文件夹,实现工程和源文件之间的关系,而不用实际把源文件复制到工程目录下。 EIDE工程和源文件实现分开放置,EIDE(EIDE工程)、EWSTM8(IAR STM8工程)、Project(ST Visual Develop工程) 选择工具链 烧录工具选择 头文件包含目录 添加宏定义 3. 编译 4. 使用STM8

TrueLink的博客 5500

数组名不是数组?C语言函数参数中退化为指针的4种典型场景分析

掌握C语言数组名作为函数参数退化为指针的原理,解析4种典型应用场景与应对策略,避免常见错误,提升代码健壮性。深入理解形参传递机制,值得收藏。

ProceSeed的博客 843

SAP OBYC自动过账全解析:从BSX到WRX的会计科目配置指南

本文深入解析SAP OBYC自动过账功能,从BSX到WRX的会计科目配置全流程,涵盖评估分组代码、事务码和评估类等核心概念。通过实战案例展示如何实现库存变动到财务过账的自动化流转,提升企业财务数据的准确性和效率。

weixin_29239279的博客 416

【C语言核心知识点】:数组名作参数时退化为指针,这3种解决方案你必须掌握

掌握C语言数组名作为函数参数退化为指针的3种解决方案,解决无法获取数组长度等问题。适用于函数传参、多维数组处理等场景,提升代码健壮性与可维护性,值得收藏。

Instrulink的博客 932

深入了解 Google Gemini:主要功能是什么以及我们为什么要使用它?

Google Gemini开启AI新纪元,以其独特的多模式功能重塑技术未来。

KompasAI的博客 4061

ROS智能车定位导航仿真+功能包自带的地图实现+自己建立的地图实现

ROS智能车定位导航仿真一、前言二、效果图三、准备工作[1.在Ubuntu上安装ROS Kinetic](https://blog.youkuaiyun.com/qq_42585108/article/details/104327661)2.创建ROS工作区间①1创建racecar_ws和src文件夹②初始化工作空间③下载racecar源代码包,并编译工程四、启动仿真1.设置环境变量2.启动地图五、建图1.启动slam和rviz2 控制车辆(左侧有个控制窗口),WASD控制前左后右的运动就可以建图了:3.新建终端保存地

qq_42585108的博客 1万+

为什么不建议函数有太多参数?

函数参数是如何传递的?

3553

054_小驰私房菜_Camx i2c读写相关备忘

Camera 对Ae、Af这些控制,实际都是,最终实际都是落实到hal下发相关的指令给驱动,那hal这边是怎么给驱动下发相关命令的呢?#小驰私房菜054# #Qcom Camx#可以参考看下下面相关代码内容。

148

【C语言数组参数长度计算终极指南】:揭秘99%程序员忽略的传参陷阱

掌握C语言数组参数的长度计算关键技巧,解决函数传参时长度丢失难题。适用于嵌入式、算法等场景,详解sizeof与指针陷阱,揭示正确获取数组长度的方法,提升代码健壮性,值得收藏。

SimSolve的博客 753

基于Simulink的异步电机定子磁链定向控制(SFOC)仿真

本文带你从零构建了异步电机SFOC系统​ 的完整Simulink仿真模型,实现了:✅ 搭建异步电机、逆变器、风机负载的主电路与传感器模型;✅ 用MATLAB Function实现定子磁链观测(电压模型)、坐标变换、双闭环PI控制;✅ 验证SFOC在转速跟踪(响应0.2s、超调4%)、转矩响应(恢复0.15s)中的高性能;✅ 对比RFOC,明确SFOC在参数鲁棒性(转子电阻+50%时波动<2%)上的独特优势;✅ 理解SFOC“定子磁链定向+解耦控制”的核心思想(低成本高鲁棒性驱动的工程实现)。

xiaoheshang_123的博客 389

173、NPU的编译器开发:开源社区贡献指南

本文分享了在NPU编译器开源社区贡献的经验心得。作者通过实际案例(如卷积维度错误、NaN输出等)阐述了NPU编译器开发的特殊性:硬件迭代快、边界条件复杂、厂商代码不可全信。提出有价值的贡献应聚焦硬件适配测试、性能剖析工具和反模式文档三类内容。强调用实测数据沟通、主动承担维护责任、保持代码通用性等社区协作技巧,并建议通过RFC提前沟通、附硬件实测数据等方式提高PR通过率。最后指出,NPU编译器开发是与聪明人共同填坑的过程,鼓励开发者提交"有诚意的代码"而非完美代码。

m0_50546716的博客 35

C 语言指针进阶详解(二):数组与指针的深度绑定

本文深入解析C语言中指针与数组的核心关联。主要内容包括:1)数组名的本质在大多数情况下是首元素地址,但存在sizeof和&操作两个例外;2)数组访问本质是指针运算,arr[i]等价于*(arr+i);3)一维数组传参实际传递的是地址而非整个数组;4)二级指针用于存储指针变量的地址;5)指针数组可模拟二维数组功能。文章通过代码示例详细演示了指针遍历数组、冒泡排序实现等实用技巧,并预告后续将讲解数组指针、函数指针等进阶内容。

hwtwhy的博客 641

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

C语言数组深度解析:从内存布局到实战应用

数组作为计算机科学中最基础的数据结构,本质上是连续内存块的抽象实现。在C语言中,数组不仅是存储数据的容器,更是理解指针运算、内存管理等核心概念的关键。通过分析内存布局可以发现,数组元素在物理地址上的连续特性,直接影响着缓存命中率和程序性能。在工程实践中,正确使用一维/二维数组、避免越界访问、合理选择静态分配与动态内存管理,是开发高效稳定C程序的基本功。本文特别针对动态数组实现、VLA变长数组应用等热点问题,结合内存优化、缓存友好访问等实战技巧,帮助开发者掌握数组在数据结构实现、算法优化等场景中的高阶用法。

weixin_33688840的博客 464

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

3.数组和指针【由浅入深.c】

本文介绍数组和指针相关内容。(【由浅入深】是一个系列文章,它记录了我个人作为一个小白,在学习c++技术开发方向计相关知识过程中的笔记,欢迎各位彭于晏刘亦菲从中指出我的错误并且与我共同学习进步,作为该系列的第一部曲-c语言,大部分知识会根据本人所学和我的助手——通义,DeepSeek,腾讯元宝等以及合并网络上所找到的相关资料进行核实誊抄,每一篇文章都可能会因为一些错误在后续时间增删改查,因为该系列按照我的网络课程学习笔记形式编写,我会使用绝大多数人使用的讲解顺序编写,所以基础框架和大部分内容案例会与他人一样,

插花弄玉的博客 1132

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C语言数组从入门到精通:内存布局、指针操作与冒泡排序实战

数组是编程中用于存储同类型数据集合的基础数据结构,其核心原理在于使用连续的内存空间进行高效的元素访问。理解数组与指针的等价关系是掌握C语言内存管理的关键技术价值,这直接关系到程序的性能和稳定性。在实际工程中,数组广泛应用于数据排序、字符串处理和矩阵运算等场景。例如,冒泡排序作为经典的入门算法,通过相邻元素比较和交换实现排序,其优化策略如提前终止能显著提升对近乎有序数据的处理效率。本文聚焦于C语言数组的声明、初始化、内存布局及指针操作,并深入剖析了冒泡排序的实现与优化,旨在帮助开发者夯实基础并应用于实际项目。

weixin_30321709的博客 365

C语言、SQL、CUDA开发踩坑总结:从语法细节到异构编程实战

最近在整理代码笔记的时候,发现不管是初学C语言指针、写SQL查询语句,还是上手GPU异构开发(CUDA / OpenCL),很多坑并不是语法看不懂,而是底层执行逻辑理解不到位。本文结合平时刷题、项目踩坑经验,梳理C语言指针数组、for循环细节、SQL执行顺序、CUDA内核改写OpenCL实战问题,适合在校学生、初学后端与GPU编程的开发者参考。实战经验:移植大型CUDA内核的时候,不要一次性全部改写,优先单函数移植、单元测试,逐行对比输出结果,排查精度、下标越界问题。这句话不完全正确,是最经典的误区。

2601_96442678的博客 155

360研发笔试题深度拆解:数组指针、Linux与系统底层考点全解析

研发岗位笔试通常不是死记硬背的战场,而是对技术基本功与工程直觉的综合检验。从最基础的数组与指针出发,理解数组名在sizeof与取地址场景下的语义差异、指针运算的步长规则,再到函数传参时数组退化为指针的本质,这些知识点直接映射到内存布局与系统资源掌控能力。操作系统中的进程线程同步、死锁条件、虚拟内存管理,以及Linux下进程查看、端口排查、软硬链接等常用命令,同样是区分候选人是否具备真实工程经验的分水岭。配合数据结构与算法中的链表反转、二分查找、二叉树遍历等高频题型,以及Java方向JVM内存区域和线程池参数

weixin_34037173的博客 384

1.数据,运算符和输入输出【由浅入深.c】

本文介绍数据类型和变数据,运算符和输入输出相关内容。

插花弄玉的博客 1224

C语言程序结构详解:从main函数到模块化工程实践

在编程学习中,理解程序的整体结构往往比死记语法更重要。无论是新手还是有一定经验的开发者,掌握代码的组织方式、入口函数的职责以及模块之间的协作关系,都是写出可维护程序的基础。程序结构决定了代码的执行流程,从预处理指令、全局变量、函数定义到主函数,每一部分都承担着特定角色。清晰的程序结构不仅提升代码可读性,还能显著降低调试与维护成本。在工程实践中,它广泛应用于课程设计、嵌入式开发及大型项目协作,而头文件拆分、条件编译和模块化设计正是从零散代码迈向工程化应用的关键一步。本文以C语言为载体,逐层剖析程序框架的组成要

weixin_28683689的博客 321

为什么你的C函数被误改数据?深入剖析const指针传参的4个常见错误

掌握C语言const指针的函数参数传递技巧,避免数据被意外修改。解析四种常见错误场景,阐明只读保护机制与实际应用方法,提升代码安全性与稳定性。深入理解const在指针传参中的作用,值得收藏。

LiteCompile的博客 1112

C语言中,数组名作为参数传递给函数时,退化为指针

C语言中,数组名作为参数传递给函数时,退化为指针;需要数组大小时,需要一个参数传数组名,另一个传数组大小。 数组名做函数参数时,就相当于指针了。sizeof对指针操作结果应该是4。   一般函数参数为数组时,可以有两个参数,一个数组名,一个数组长度的。 首先C语言里面不支持数组作为形参来进行调用 例如函数void fun(int a[]);里面的a实际上在进行编译时,是作为

foreverhuylee的专栏 1万+
上一篇: 为什么你的C程序总在生产环境崩溃?Valgrind帮你找出隐藏内存漏洞
下一篇: C语言程序员必知的10个内存细节(全局与局部变量存储位置全曝光)
IterLoom
博客等级 码龄1年 171粉丝 2173原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值