不得不聊的关于方法的参数的那些事儿

本文深入探讨了方法参数的本质,解释了为何定义形参需传递实参,介绍了参数默认值的设定及其限制,并讨论了如何显式为形参传递实参。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  很多朋友在看了这个标题之后,可能会以不屑的眼神看着我说,"去,我xx年的编程经验,难道方法(函数)还有什么不知道的么?你可要记住,从我开始学编程的那1天起就已经开始每天都在写方法了."  当然我不会从最基本的说起,更多的我希望说说我自己的的理解以及原理,所以这篇文章仅仅是个人总结,可能会由于个人知识面比较窄的原因会存在一些瑕疵,请大家不吝指教.好了,那我们就开始吧.

     

 

 

  a. 为什么定义了形参,就一定要传递实参?

  谁都知道,如果1个方法定义了参数,那么我们在调用这个方法的时候,就必须要为这个方法的参数赋值.比如下面这样.

           

   如果不传递的话,谁都知道这将是1个什么样的后果.

    

   但是又有谁想过为什么是这样的呢?为什么方法定义了参数,我们在调用的时候就必须要为其传递实参呢?反正之前我是没有想过这个问题的,仅仅是这样的1句话就将自己打发,"那是微软规定的语法". 后来仔细想了一下,我认为之所以是这样,是因为方法的参数本质上是这个方法的1个局部变量.所以我们可以在方法中直接使用这个参数,并且你也不能再这个方法中定义1个名字和参数的名字相同的变量.我们说将实参传递给形参实际上就是将实参的值赋值给形参的1个过程.而局部变量有1个最重要的特点就是使用之前必须赋值.但是我们在声明这个参数的时候却没有为它赋值,仅仅是声明了而已.所以如果调用者要执行这个方法中的代码,而在这个方法中是有可能会用到这个参数的.所以要求调用者在调用方法的时候必须要为形参赋值.

  对于方法的参数的本质是方法的局部变量这1个说法,估计有童鞋会有意见.

    

    正如上面这段代码.你会发现我们在这里可以直接使用参数,但是参数是没有值的.这个时候是不会报错的(使用了未赋值的局部变量).原因很简单.因为方法中的代码只有在方法被调用的时候才会执行,而这个方法如果被调用,那么调用者就必须要为参数传值,所以当这个方法中的代码运行起来以后,参数str中绝对肯定已经有值了.

  所以我们的结论是: 方法的参数本质上是这个方法的局部变量,而局部变量在使用之前必须要有值.而我们在声明形参的时候没有为形参赋值,所以要求调用者在调用的时候必须赋值,如果不赋值的话,在方法中使用到形参的时候会因为形参没有被赋值而报错.

  b.方法的参数的默认值.

  从上面我们可以知道,之所以一定要为形参传递参数是因为形参没有值.那如果是因为这样话我们可以不可以在声明形参的同时就为这个形参赋1个默认值呢?答案当然是肯定的.原因嘛很简单,刚才才说了 定义1个方法的参数其实就是声明了1个方法的局部变量,那我当然可以在声明这个局部变量的同时为这个局部变量赋值了.

    

    这个时候,我们发现我们在声明方法的参数的同时为这个参数赋了1个默认值,那就意味着这个局部变量已经有值了,如果调用者希望执行这个方法中的代码,大可不必一定要为这个方法的参数传值.完全可以不传值.方法仍然会执行,不会报错.再一次证明了方法的参数的本质是这个方法的1个局部变量.

    当然了,如果我们在调用带默认值的参数的方法的时候,不传值的话,在方法的内部会直接使用其默认值.如果调用者希望这个值是自己指定的值,那么就只有选择自己传递了.

   

  所以,我的总结是:如果方法的参数的值不一定要求调用者指定,就可以为这个参数指定默认值,调用者根据具体的情况来选择传递还是不传递.如果调用者希望这个参数使用默认值那么就可以选择不传递,如果不希望使用默认值而是调用者自己指定,就自己选择为参数传递值.

  在为方法定义带默认值的参数的时候必须要注意第1个问题.所有的带默认值的参数必须出现在参数列表的最右侧.换句话说,带默认值的参数必须出现在参数列表的最后面.

   

   我们将带默认值的参数放在参数列表的最右侧,才可以滴.原因很简单.我想不解释了吧.因为编译器不知道我们到底是要给那1个形参传递参数.

  关于方法的参数的默认值注意的第2个问题:参数的默认值必须是编译时就可以确定的值.如果我们为参数的默认值赋值1个运行时才确定的变量的话,那么这个时候编译器是会报语法错误的.

   

  第3个要注意的问题:ref/out修饰的参数不能有默认值,那关于这个的原因,我想应该不难理解.因为ref/out要求传递变量的地址,而不是变量的值,所以就算可以给值也是没有任何实际意义的.

   

   第4个要注意的问题: params修饰的数组参数仍然需要放在参数列表的最后,而不是放在默认值参数的最前面.

     

   c. 显示的为形参传递实参.

    正如我们前面所说,方法的参数可以有默认值,它的好处在于可以不给带默认值的参数传递实参,但是很快我们发现1个困扰我们的问题了.

    

    看看上面这个方法,假如我们作为调用者只希望给形参str赋值,我们该如何传参呢?我们试着这样调用.

    

    我们却发现,它将字符串"testString"传递给了形参name,原因很简单嘛。我们知道在传递参数的时候,编译器会按照顺序将实参1个1个的赋值给形参,所以不奇怪的将实参"testString"赋值给了第3个形参.

    那到底该如何解决呢? 不急,先带大家看1下我们经常看见的1个现象,但是很少去深究,起码我之前是这样的.当我们在调用1个方法的时候,并为这个方法的参数传递实参的时候,Visual Studio会做如下提示:

    

    这个时候VS自动提示的name:是个什么东西呢?以前也有朋友问过我这个问题,当时我支支吾吾半天没说出个所以然.现在总算搞清楚了,这个其实就是方法的形参名.通过方法的形参名我们可以指定为那1个形参赋值,看下面的代码吧.

   

   这个时候你会发现,程序运行的时候,不再是按照顺序将实参的值赋值给形参了,而是根据我们指定的形参来赋值的了.这样就可以解决我们之前的那个问题了.

   好了,今天就到这里了.对于一些大牛而言,可能这些东西早已知晓,本人在园子里发这篇博文也是希望给自己做1个小的总结.难免会有纰漏,请大家指点.

转载于:https://www.cnblogs.com/highven/p/3193633.html

### C语言中线程的创建方式 在C语言中,主要通过POSIX线程库(`pthread`)来管理多线程操作。以下是三种常见的创建线程的方式: #### 使用 `pthread_create` 这是最常见的一种方法,用于启动一个新的线程。 ```c #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); ``` 此函数接受四个参数:新线程ID指针、属性结构体、入口函数及其参数[^1]。 #### 预定义线程属性设置 有时需要自定义线程的行为,比如栈大小或调度策略,则可先设定线程属性再调用`pthread_create()`: ```c pthread_attr_t attr; pthread_attr_init(&attr); // 初始化属性对象 // 设置特定属性... pthread_create(&tid, &attr, thread_function, arg); ``` #### 继承父进程环境创建子线程 另一种较少见的情况是从现有线程继承某些特性来派生新的工作单元,这通常涉及更复杂的配置选项,在标准应用开发场景下并不常被采用。 ### 线程运行机制 线程作为操作系统能够进行运算调度的最小单位之一,其基本运作依赖于CPU的时间片分配算法。多个线程可以在同一进程中并发执行,共享相同的地址空间和其他资源,从而减少了上下文切换开销并提高了效率。为了防止不同线程间的数据冲突,必须采取适当的同步措施,如使用互斥锁和条件变量等工具。 ### 常见API函数 - **`pthread_join`**: 主要用来阻塞当前线程直到指定的目标线程结束为止。 ```c int pthread_join(pthread_t th, void **thread_return); ``` - **`pthread_exit`**: 提供了一种优雅退出正在运行中的线程的方法,并可以选择返回给定的结果值。 ```c void pthread_exit(void *retval); ``` - **`pthread_mutex_lock/unlock`**: 对临界区加解锁以保障数据的一致性和完整性。 ```c int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); ``` - **`pthread_cond_wait/broadcast`**: 实现基于事件的通知机制,允许一个或多个等待线程继续执行。 ```c int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_broadcast(pthread_cond_t *cond); ``` 这些接口共同构成了处理线程安全问题的基础框架。 ### 线程生命周期状态 线程在其整个生命期内会经历几个不同的阶段: - **新建态(New)**: 当成功调用了`pthread_create()`之后即进入该状态;此时虽然已经分配好了必要的内存但是还没有真正开始执行任何任务。 - **就绪态(Ready)**: 准备好随时由处理器调度去完成自己的使命;处于这种状态下意味着它只差获得CPU时间就可以正式启动起来做事情了。 - **运行态(Running)**: 获得了CPU使用权后便进入了实际工作的环节——按照既定逻辑顺序依次处理各项指令直至遇到I/O请求或其他原因被迫暂停下来让位给别人。 - **阻塞态(Blocked)**: 如果因为等待某个外部事件的发生而暂时无法前进的话就会陷入这样的停滞局面里头;例如读取文件失败重试超时之类的状况都可能导致此类现象发生。 - **终止态(Terminated)**: 完成了所有的预定动作或是遇到了致命错误不得不提前收场的时候便会来到这里;这时除了清理现场之外不会再有任何实质性的活动发生了。 以上便是关于C语言环境下如何利用POSIX API来进行高效稳定的多线程编程的相关介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值