人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

09 | 函数:自己动手实现低配版 scanf 函数

你好,我是胡光,今天是大年初一,是咱们中国传统的重要节日,春节!能在这样的节日氛围里,还能坚持过来学习的,我必须要说一声“鼠”你最优秀!在这里我也祝福热爱学习的你,在新的一年,身体健康,阖家欢乐!
今天呢,我们的学习课程也将迎来里程碑式的一课。所谓里程碑,是因为在这一节之前,你写的程序,只是片段,只是思想的随意表达,而通过了本节的学习,你的程序结构将发生翻天覆地的变化,会变得规格严整,变得可以复用,变得易于找错。
前面的课程,我们主要就是在一些基本的程序结构中做学习,包括顺序结构,分支结构以及循环结构。今天这一节中,我们将要认识的函数,可以将功能封装成可以复用的模块,就像创造乐高积木一样,废话不多说,开始今天的学习吧。

今日任务

对程序的输入输出函数,你应该已经很熟悉了。今天我们仿照 scanf 函数,实现一个低配版的 my_scanf 函数。这个函数的功能,简单来说就是将一个字符串信息转换成整型数字,能够完成这个任务,你会更深刻的理解 scanf 函数,更深刻的理解参数设计。下面给你几个例子。
首先先来看第一个基础功能:
int n = 98;
my_scanf("12345", &n);
printf("%d", n); // 输出 12345,而不是 98
上面这段代码中,我们利用 my_scanf 函数,将字符串信息转换成了整型数据,并且将结果存储到了 n 变量的内存空间中,调用 printf 函数打印 n 变量值的时候,输出的信息不是 n 变量原有的初值 98,而是 12345。对于这个基础的转换功能,要考虑兼容负数的情况。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何自己动手实现低配版 scanf 函数。作者首先提到了函数的重要性,将功能封装成可以复用的模块,就像创造乐高积木一样。接着,文章列举了两个例子,展示了 my_scanf 函数的基本功能和对负数的兼容情况。然后,作者提出了今日任务,即实现一个能够转换任意个整型参数的 my_scanf 函数。在必知必会环节中,文章详细介绍了函数的基础知识和普通变量的函数传递参数过程。通过示例程序和图示,读者可以清晰地了解函数的组成部分、参数传递过程以及形参和实参的关系。整体而言,本文内容涵盖了函数的基础知识和参数传递过程,适合初学者快速了解和掌握相关知识。文章还提出了两个思考题,引导读者思考数组和函数的异同以及如何确定存在知识的盲区。最后,通过实现 my_scanf 函数的例子,读者可以进一步学习“可变参函数”的相关知识。整体而言,本文内容涵盖了函数的基础知识和参数传递过程,适合初学者快速了解和掌握相关知识。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(18)

  • 最新
  • 精选
  • 🤪HappyJoo
    思考题一: 同: 1,返回整型 2,函数需要传入参数,但是数组在这个角度看,也是需要在[]中“传入参数”,测试了一下,数组的[]好像是不能空着的,函数理论上也是不能空着的。 异: 1,数组只能一次返回一个,函数可以返回多个 2,数组存储整型,函数需要进行函数内的步骤然后返回,它本身不存储。也就是说数组占用空间,函数不占用? 3,从某个角度来看,数组的数值是固定的,都是你事先存储进去,然后取出,而函数可以修改,看你想要什么结果,都可以修改得到,可变化。 问题: “而“传出参数”由于要把值从函数中带出来,一般要传变量地址进去,这样,函数内部才能准确的把结果写入到相关地址所对应的内存中。” 老师你好,你的课程真的太棒了,讲解的也非常适合零基础的人,我以后向人推荐就推荐这门课了哈哈哈哈~请问一下,为什么一定要传变量地址呢?不能直接整型进去整型出来嘛?为什么不能直接传内容,而要传地址呢?传内容就不准确了?或者效率不高? 按照我的理解,函数就是拿来用的,参数进去,经过函数“整改”,“计算”出我想要的东西,再传回来。这进去和出来的东西,当然和这个函数无关,就好像我要毁灭你与你无关,哦不对,就好像算法一样,我把生米放进去,它把熟米吐出来,不管是生米还是熟米,和这个电饭煲是没有关系的。所以为什么要把地址作为参数传出来,而不是直接把“米”传回来呢? 谢谢老师~

    作者回复: 首先你对于函数和数组的思考这里,已经很接近标准答案了!思考的很到位。后面的答疑文章中,会讲到『数组是展开的函数,函数是压缩的数组』。 其次,对于你的问题: 传地址的话,那么地址就是你所传进去的那个内容。 函数的参数变量,和你外部调用函数时候的变量,实际上是两个变量。无论你传什么内容,函数的参数都是独立的一个变量,就算你传递的是地址,也不过是把这个地址值,存储到了函数参数变量中。而函数内部,有了这个地址值,就可以准确的对应到相应的存储区,从而可以改变地址所对应存储区中的值。 就拿你说的米来举例子,你有一个【A麻袋】里面装着米,麻袋就是变量,米就是变量中的内容,然后函数传参,就相当于你把【A 麻袋】复制了一份,复制成了 【B 麻袋】,B 麻袋,就是函数参数,然后在函数内部,无论你怎么对 B 麻袋中的内容做修改,都不会影响 A 麻袋的。

    2020-02-12
    6
  • 徐洲更
    知识点: 1. 函数的实参和形参,形参修改不会修改实参 2. 为了在函数中更改函数外的参数,可以传入指针,直接修改内存里的内容 3. 快速将'0'-'9'字符转成数字0-9的方法, '9' - '0' 4. 流处理方式转换字符串为数字, num = num * 10 + (str[i] - '0') 题目做题过程在GitHub上, https://github.com/xuzhougeng/learn-c-in-JKSJ/blob/master/jksj-09-myscanf

    作者回复: 不错!作业题目做的很棒。完全达到了自学的要求!

    2020-01-25
    5
  • 落曦
    思考题一 第一个是申请的占用连续内存空间的数组元素 第二个是申请100个整型数据,内存空间不一定连续 数组只能一次返回一个,函数可以返回多个

    作者回复: 只说了他两的不同点,相同相同点呢?

    2020-03-31
    3
  • 吕作晶
    老师,是不是也可以介绍下函数指针?指针函数?这个概念一直没有搞明白过~

    作者回复: 这就是文人墨客咬文嚼字的东西。不过你可以这么理解,本质的概念,都放到后面。例如,整型数组,本质是个数组。函数指针,本质是个指针,指向函数的指针,指针函数,本质是个函数,返回指针类型的函数,没啥特别的。

    2020-03-29
    2
    1
  • rocedu
    看函数参数时,只要是指针类型,就要注意是不是输出参数了。另外,为什么要输出参数,很多API的返回值都是错误码,0表示成功,其他表示错误类型,功能值需要通过输出参数传出来。

    作者回复: d(^_^o)

    2020-02-10
    1
  • 罗耀龙@坐忘
    茶艺师学编程 1、 总于搞明白了文中的“普通变量传递”例子其中的,搞出了个可以传递数值的版本…… #include <stdio.h> int add(int n,int m){ //这里要改为有返回值类型     n += m;     return n ; //返回n } int main(){     int n, m;     scanf("%d%d", &n, &m);     printf("%d\n", add(n ,m)); //调用上面的add函数     return 0; } 2、 思考题1: 共同点,两者样子相似 不同点,前者仅仅是一个“片段”,后者则是具备某基本功能的“小个体”。 思考题2: scanf int scanf(char *format[,argument,...]); scanf("<格式化字符串>",<地址表>); scanf()函数返回成功赋值的数据项数,出错时则返回EOF。

    作者回复: 再想一想,函数所谓的基本功能,对于我们来说真得重要么?我们其实只关心,函数传入什么参数,返回值是什么含义。数组呢?我们只关心,数组相应下标里面记录的值是什么含义。

    2020-05-22
  • Aureliano
    老师,可变参数代码如下: #include<stdio.h> #include<stdarg.h> void myscan(char* string,...){ int *p=NULL; int flag=0; int num=0; int i=0; va_list pa; va_start(pa,string); p=va_arg(pa,int*); for(;string[i]!='\0';i++){ if(string[i]==' '){ if(flag==1){ *p=-num; }else{ *p=num; } num=0; flag=0; p=va_arg(pa,int*); }else{ if(string[i]=='-'){ flag=1; }else{ num=num*10+string[i]-'0'; } } } if(flag==1) { *p=-num; } else{ *p=num; } va_end(pa); return; } int main(){ int m,n,k; myscan("123",&n); printf("%d\n",n); myscan("123 -456",&m,&k); printf("%d\t%d\n",m,k); return 0; }

    作者回复: d(^_^o)很不错!

    2020-02-25
  • 信念
    请问一下,在老师的最后一个文本中,ret所指向的存储区为什么是主函数中n变量的内存区呢?怎么看出来的?

    作者回复: 因为在主函数中,调用 my_scanf 函数的时候,传入的是 n 变量的地址啊。

    2020-02-12
  • 信念
    #include<stdio.h> int main(){ int n = 98; my_scanf("12345", &n); printf("%d", n); // 输出 12345,而不是 98 return 0; } 这是老师您的程序,但是在我编译时出现了问题,问题如下,麻烦老师看一下: test35.cpp: In function ‘int main()’: test35.cpp:4:3: error: ‘my_scanf’ was not declared in this scope my_scanf("12345", &n); ^~~~~~~~ test35.cpp:4:3: note: suggested alternative: ‘vsscanf’ my_scanf("12345", &n); ^~~~~~~~ vsscanf 好像是说没有声明my_scanf

    作者回复: 你误会了,我的那段代码是说明my_scanf函数的功能的。而没有my_scanf函数的具体实现,只有加上了具体实现以后,代码才能通过编译。

    2020-02-09
    2
  • 小林coding
    老师,我的可变参数的myScanf函数 代码: #include <iostream> #include <stdarg.h> void myScanf(const char *format, int *pInt, ...) { va_list ap; int *p = NULL; int num = 0; int cnt = 0; va_start(ap, pInt); while (*format) { if (*format == ' ') { if (cnt == 0) { *pInt = num; } else { p = va_arg(ap, int*); *p = num; } num = 0; cnt++; } else { num = num * 10 + *format - '0'; } format++; } p = va_arg(ap, int*); *p = num; va_end(ap); } int main() { int n, m, j; myScanf("123 456 789", &n, &m, &j); std::cout << n << " " << m << " " << j << std::endl; return 0; } 输出: 123 456 789

    作者回复: 可以打80分,稍微有点儿缺憾的就是:没有考虑负数的情况哦。d(^_^o)

    2020-02-01
    2
收起评论
显示
设置
留言
18
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部