C语言第二课:main调用了test,为什么test看不见main里的变量?

保姆级教程:在Rockchip RK3588 SDK中,如何为你的新硬件板子创建第一个DTS文件 本文提供在Rockchip RK3588 SDK中为自定义硬件创建首个DTS文件的详细教程。通过分析DTS在RK3588开发中的角色、快速定位参考设计、实操步骤及调试验证方法,帮助开发者高效完成硬件板级配置,特别适合嵌入式Linux系统开发者参考。 阅读详情

main里面有一个a,值是100。它调用test,test里面直接打印a,可以吗?

#include <stdio.h>
void test(void)
{
    printf("%d\n", a); /* 错误:此处没有可见的 a 声明 */
}
int main(void)
{
    int a = 100;
    test();
    return 0;
}

如果顺着运行过程想,会觉得main的a已经有值了,怎么还报没有声明?这里先别背“局部变量”四个字。我们把“代码写在哪里”和“执行时从哪里过来”分开。

test被调用了,但它没有写进main的大括号

test的函数体是独立定义的。编译器检查那行printf时,这个位置没有可见的a声明;运行时谁调用它,不能倒过来改变名字的查找范围。

对照一下:main里面再套一个普通代码块,这层确实写在main内,可以用外层的a。test要用这个数,则可以让调用处把值交给它:

#include <stdio.h>
static void test(int value)
{
    printf("test:%d\n", value);
}
int main(void)
{
    int a = 100;
    {
        int b = 20;
        printf("inner:%d,%d\n", a, b);
    }
    /* 这里能使用 a,不能使用上面那个 b。 */
    test(a);
    return 0;
}

输出是inner:100,20和test:100。普通内层块可以看到外层a,独立函数使用的是自己的形参value。调用处的test(a)把100交过去,并没有让test获得main里面那个名字。

main里的a通过实参把100交给test的value,调用线不是作用域包含线

这时如果把形参也命名为a,它仍是test自己的变量。名字相同,不能把两个对象合并。

那我原来这段“函数”为什么能打印100

#include <stdio.h>
int main(void)
{
    int a = 100;
    void test(void);
    {
        printf("%d\n", a);
    }
    return 0;
}

注意void test(void);后面的分号。到这里是一条函数声明,已经结束了。后面的花括号是main内的普通代码块,不是test的函数体;程序里也没有调用test。

所以输出100本身没错,错的是把它当成“独立函数可以访问调用者局部变量”的证据。

标准C不允许在一个函数体内再定义另一个函数。先辨认这段代码到底声明了什么、执行了什么,再解释它的输出。

同名变量出现时,到底修改了哪一个

再看一个更容易混淆的情况:

#include <stdio.h>
int main(void)
{
    int a = 100;
    {
        int a = 20;
        printf("inside=%d\n", a);
    }
    printf("outside=%d\n", a);
    return 0;
}

先在内层打印20,再在外层打印100。看起来像a先变20,出了块又恢复100,但这次根本没有“恢复”动作。

内层那句有int,新声明了另一个对象。在内层使用a,找到的是这个新声明;离开它的范围后,再使用a,找到的是外层声明。外层那个100一直没被改过。

把内层的int a = 20;换成a = 20;,再运行一次。这次没有新声明,就会修改原来的对象,外层也打印20。

内层写法内层a对应谁外层最后的值
int a = 20;新声明的内层对象100
a = 20;已经可见的外层对象20

所以看到赋值,先找到这一行里的名字绑定到哪个声明。不能只看整篇程序里有没有另一个也叫a的变量。

名字看不见了,对象就一定没了吗

刚才讨论的是“在哪能使用这个名字”。但函数返回后,对象还能不能保留,是另一个问题。

#include <stdio.h>
static int next_count(void)
{
    static int count;
    return ++count;
}
int main(void)
{
    int first = next_count();
    int second = next_count();
    printf("%d,%d\n", first, second);
    return 0;
}

输出是1,2。局部static的count不会每次调用都重新从0开始;第一次加到1,第二次接着加到2。

可是在main里直接写printf("%d", count),依然看不见这个名字。对象在两次调用之间保留着,不等于这个名字对整个程序都可见。

这时再区分两个词就有具体对象了:作用域决定名字在哪可见,存储期决定对象存在多久。

回到开头,test究竟需要什么

如果test只需要100这个值,把它作为参数传入即可。如果test还要修改main里的对象,单纯复制一个整数就不够了,需要另外传递访问那个对象的方式。

这正好接到下一课:函数改了参数,外面的值为什么有时变、有时不变。先把名字找对,再追踪复制与修改,就不会把调用、变量同名和共享对象混在一起。

动网格-网格重构之铺层(三) 运动区域可以是边界区域 (Boundary Zone),也可以是单元区域 ( Cell Zone)。指定了体网格再生方法后,FLUENT自动地根据运动区域(dynamic zones)的运动来调整内部节点以再生体网格。必须保留至少一层网格。(4)如果边面的法向和运动方向偏角较大,生成的网格扭斜度会比较大铺层算法不适用于边界形状变化较大的情况。(1)体网格再生方法的选择(Smoothing,Layering,Remeshing);(2)适用网格种类:四边形、六面体、三棱柱(网格的分布要服从一定的规则)。 阅读详情

相关推荐

WebRTC Qos优化杂记

本文是笔者对WebRTC Qos性能研究、优化的一些思考,希望对有兴趣的读者有一些启发。

sonysuqin的专栏 6675

C语言变量初始化是必须的

摘要:本文系统探讨C语言变量初始化的关键问题,通过未初始化变量的实例分析编译器警告机制(如VC++的0xCCCCCCCC填充值),揭示内存中"垃圾值"的本质。文章对比不同存储类别变量(局部/全局/静态)的初始化行为,指出常见误区:误认全局变量自动清零、条件分支遗漏初始化和指针解引用风险。通过实战代码演示,强调"定义即初始化"的最佳实践,特别针对复杂控制流和指针操作提出防御性编程方案,最终论证显式初始化对代码健壮性的决定性作用。

ywl470812087的博客 2551

IntelliJ IDEA 2025.1 + Gradle 镜像配置避坑指南:解决依赖下载慢的终极方案

本文针对IntelliJ IDEA 2025.1开发环境中Gradle依赖下载缓慢的问题,提供了详细的镜像配置避坑指南。通过解析Gradle依赖解析机制,重点指导如何正确配置阿里云等国内镜像仓库,并分享验证配置生效、排查常见错误及高级优化技巧,旨在彻底解决依赖下载难题,提升开发效率。

weixin_28835551的博客 531

C语言main函数标准写法:int main(void)为何是唯一安全选择

main函数是C/C++程序的入口点,其签名直接关联操作系统进程管理、编译器调用约定与标准合规性。根据ISO/IEC 9899(C标准)和ISO/IEC 14882(C++标准),main必须返回int类型,仅允许int main(void)或int main(int, char**)两种形式——这是保障退出状态可被waitpid等系统调用正确读取的技术前提。void main()属于未定义行为,虽在部分编译器(如旧版MSVC)中可静默通过,但在GCC -std=c17、Clang -Weverything

weixin_30247781的博客 384

el-upload自定义上传dwg/dxf文件并且携带额外参数(CAD)

需求:需要使用el-upload自定义上传cad的图片或普通图片,这边需要判断区分下,以及上传后清空上传文件列表。

请叫我欧皇!的博客 1535

TMC5130/TMC5160步进电机驱动芯片深度解析与工程实践

步进电机驱动芯片是精密运动控制系统的物理执行核心,其性能直接决定定位精度、运行噪声与系统鲁棒性。基于电流闭环控制与电压前馈调制的混合驱动原理,现代智能驱动芯片如TMC51X0系列实现了微步插补、堵转检测和片上运动规划等关键技术突破。这类芯片通过SPI寄存器级配置实现StealthChop静音驱动与SpreadCycle高动态响应模式的无缝切换,在3D打印、CNC、机器人关节等场景中显著提升能效比与控制带宽。本文围绕TMC5130与TMC5160的硬件架构差异、寄存器操作时序、驱动模式物理机制及FreeRTO

weixin_35797963的博客 407

C语言基础-14变量

变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示:type表示变量的数据类型,可以是整型、浮点型、字符型、指针等,也可以是用户自定义的对象。可以由一个或多个变量的名称组成,多个变量之间用逗号,分隔,变量由字母、数字和下划线组成,且以字母或下划线开头。下面列出几个有效的声明:定义整型变量:int age;以上代码中,age 被定义为一个整型变量。

jiang_changsheng的博客 2466

WangEditor 5.0版本dangerouslyInsertHtml方法的正确使用方式

WangEditor 5.0版本dangerouslyInsertHtml方法的正确使用方式

yang1067155909的专栏 4290

小郭学C语言(一)

 问题:如何在下面的test函数里加入代码可以使程序运行起来输入和输出的相等?    (环境是vc6Debug方式下)#includevoid test(){  int t;  scanf("%d",&t);  在这里加入代码 }main(){  int m;  test();  printf("m=%d",m);} 要在

风间的专栏 1300

J204B接口数据链路的建立

介绍J204B数据链路层的建立方式

QUACK_G的博客 6546

车企自动泊车技术全解|纯视觉/多传感器融合双路线、端到端大模型革新 助力机械车位/无划线车位/极窄车位精准泊车落地

随着智能驾驶技术全面下沉,自动泊车已从高端车型专属配置,普及至十万级家用车型,成为车载核心刚需功能。但市面主流车企的泊车能力差距极大,核心差异源于传感器硬件架构、算法迭代逻辑、场景训练体系的全方位分化。传统规则式泊车算法仅适配标准划线车位,面对地库暗光、标线磨损、机械双层车位、极窄靠墙车位、无划线空地泊车等真实长尾场景极易失效。

getusushu的博客 105

C语言系列之——(3)C语言中的变量

本文系统地介绍了C语言变量的核心概念,主要内容包括:1)变量本质是命名的内存存储空间;2)变量分为局部/全局/静态三类,分别具有不同的作用域和生命周期;3)局部变量存储在栈区(未初始化时值为随机),全局和静态变量存储在静态区(未初始化时默认值为0);4)静态变量通过static关键字修饰,会延长局部变量的生命周期或限制全局变量的作用域。文章通过代码示例详细说明了各类变量的特性和内存存储机制,为理解C语言变量提供了全面指导。

progressive_bird的博客 365

CDD数据库文件制作(二)——服务配置(0x27)

主要根据诊断调查表,针对0x27服务在CDD中的每一步配置给出详细介绍 1.会话切换配置 1.1.根据诊断调查表进行信息提取 1.2.子功能添加 1.2.1.Level1安全等级1创建 1.2.2.Level3安全等级3创建 1.2.3.安全等级名字查看与修改 1.3.会话切换信息提取(应用程序下) 1.4.会话转换配置(应用程序下) 1.5.会话切换信息提取(引导程序下) 1.6.会话转换配置(引导程序下) 2.安全等级配置信息提取 2.1.安全访问配置(level1) 2.2.安全访问配置(level2

LOVE135149的博客 2928

c语言中多个cpp(h)中函数或变量的使用

当前cpp使用函数只需要满足在当前cpp使用其他cpp内函数的要求即可,不需要再考虑函数中使用的变量是否在cpp中定义 示例如下: 在test.h中定义的变量 value ; 在test.cpp中的函数func()和foo()使用变量 value; 在main.cpp中调用func()和foo()函数。//我们在调用func()和foo()的时候,并需要考虑value是在哪定义的,只需要声明一下函数即可。至于func()和foo()中是如何调用value(通过包含头文件test.h获得)我们不用去考

modi000的博客 967

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

c语言程序中的main()函数必须放在程序的开始部分,c语言程序中的main()函数必须放在程序的开始部分 答案:×...

相关问题设随机变量X的密度函数为,则c= .e339fd828a3e5af974ac21fd9ebc7f0b.gif有函数f(x,y,z),其中x∈[1900,2100],y∈[1,12],z∈[1,31]的。请写出该函数采用边界值分析法设计的测试用例函数重写与函数重载的相同之处是?: 函数 函数重载 处 函数 名中国大学MOOC: 在调用指针型函数时,如果被调函数的形参是指...

weixin_42299944的博客 2267

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C语言之变量和常量

一、内存分布 首先,常量放在全局变量区,变量放在栈区。虽然,变量和常量的名字可以相同,但是他们可是两个不同的事情啊。 二、局部优先 如果在main函数中同时出现了相同名称的变量名和常量名,那么局部有先 #include<stdio.h> int a = 100; int main(void) { int a = 10; printf("%d", a); return 0; } 但是 #include<stdio.h> int a = 100; void test() {

weixin_51574797的博客 226

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C语言指针详解

同理,在计算机中,我们想要快速在内存中找到指定的数据,需要给每个内存单元编号(相当于门牌号),有了这个内存单元的编号,CPU(中央处理器)就可以快速找到一个内存单元。n在C语言中被称为常变量,常变量的意思是,n的本质是变量,但是不能被修改,即具有常属性的变量。const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变。const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

2502_90266547的博客 6084

c51语言主函数,C51 main 函数学习以及函数跳转

C51main函数深入学习,有如下代码:#include "reg52.h"/*************本地变量声明**************/typedefvoid (*pFunction)(void);pFunctionJump_To_Application;unsigned int JumpAddress;unsigned int a=0;char i;void test(){while(...

weixin_27037521的博客 1102

linux c语言调用python脚本_在Linux上实现Python调用C语言函数

一般思路Python中内置ctypes库,需调用c编译成的.so文件来实现函数调用。假设我们所需调用的c文件名为test.c,文件里有我们需要的函数func(x,y).将.c文件编译成 .so文件gcc -fPIC -shared test.c -o test.so运行后会看到有test.so文件生成。在Python中导入C文件在当前目录下打开Pythonimport osfrom ctypes ...

weixin_39730671的博客 401

C语言返回局部变量地址为什么危险?悬空指针实战解析

指针与内存管理是C语言学习中的核心与难点,很多开发者都遇到过函数返回局部变量地址后程序行为异常的困惑。从原理上看,局部变量存储于函数栈帧,函数返回即意味着其生命周期结束,返回其地址会形成悬空指针,属于典型未定义行为。理解作用域与生命周期的差异,掌握栈帧、静态存储区与堆内存的区别,是写出稳健C代码的重要基础。在嵌入式开发、系统编程以及各类C语言笔试面试中,这类问题也是高频考点。因此,合理选择返回值方式——如使用调用者传入缓冲区、动态内存分配或返回结构体值——不仅能规避崩溃风险,还能提升接口设计的可维护性。围绕

weixin_34335458的博客 353

c语言da10位怎么发送,小郭学C语言

问题:如何在下面的test函数里加入代码可以使程序运行起来输入和输出的相等?(环境是vc6Debug方式下)#includevoidtest(){intt;scanf("%d",&t);在这里加入代码}main(){intm;test();printf("m=%d",m);}要在test函数中加入代码,影响main函数里面的变量,很明显我们要加的代码是一个赋值语句,语句的右值是我们输入的t...

weixin_30356285的博客 178

C语言初阶习题(4数组)【20】扫雷游戏

本博客和三子棋游戏比较大的区别是,三子棋游戏是写完了再总结的,本博客是边代码实现边编辑博客,所以本博客会比较详细的po出每一步骤,在每实现一个小功能的时候我们都先验证下效果,再继续下一步。

graceyun的博客 1609

C语言编译流程分析

对C语言编译流程的一个简单总结

qq_45668408的博客 659

C语言-函数

本文系统讲解了函数的定义、分类(库函数与自定义函数)、参数传递(实参与形参)、调用方式(传值与传址)、嵌套调用与链式访问,以及函数声明与定义的分离机制。重点介绍了函数递归的原理与应用,涵盖递归实现字符串长度计算、阶乘、斐波那契数列等经典例题,并指出递归在大数值下的效率问题及优化方法。同时补充了常见错误如重定义、栈溢出、全局变量使用不当等问题,强调模块化编程与static关键字对内存管理的重要性,提升代码可读性与维护性。

w37773698的博客 1365

C语言函数

在C语言中,函数(function)是指将一组能完成一个功能或者多个功能的语句放在一起的代码结构,函数有其特殊的写法和调用方式。形参和实参各自是独立的内存空间,形参是实参的一份临时拷贝。作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的变量并不总是有效(可用)的,而限定这个变量在整个程序中所能够使用的范围,就称为该变量的作用域。生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段。

m0_62183318的博客 830

[C语言]学习之路

实例:C语言编程题 求100到300之间所有素数 #include <stdio.h> int main(void) { int i,j; for(i = 100;i <= 300; i++) { for(j = 2; j <= i; j++) if(i%j == 0) break; if(j == i) printf("%-4d",i); //-4d是左对齐 } return 0; } 预备计算机知识 汇编语言是最低级的语言,它可

孤桜懶契 3029
上一篇: 小菜的C语言之路——第一课——启程
下一篇: 两道C入门题:scanf多组输入怎么判断,最大最小值怎么初始化
咔_
博客等级 码龄4年 948粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值