精华内容
下载资源
问答
  • c语言 有趣简单编程 Java是我专业学习和使用第一门语言。 大约十年半以来,这一直是我生计。 但是,这并不是我一整年以来一直学习或使用唯一语言:例如,很久以前,我不得不开发JavaScript代码来实现动态用户...

    c语言 有趣简单编程

    Java是我专业学习和使用的第一门语言。 大约十年半以来,这一直是我的生计。 但是,这并不是我一整年以来一直学习或使用的唯一语言:例如,很久以前,我不得不开发JavaScript代码来实现动态用户界面。 那时,它被称为DHTML ....几年前,我还自学了Kotlin,从未停止使用它。 去年,在一家新公司工作时,我尝试了Clojure-尽管效果不佳。

    在所有情况下,Java仍然代表着我学习和判断其他语言的基础。 这是语言的一些有趣特征,我发现这些特征来自Java背景,颇具挑战性。

    JavaScript:原型

    JavaScript是我必须与Java一起使用的第一语言。 尽管JavaScript在过去的这些年里一直在发展,但其中一个共同的功能却非常奇怪地实现了:新对象的实例化。

    在Java中,首先创建一个

    publicclassPerson{
    
      privatefinalStringname;
      privatefinalLocalDatebirthdate;
    
      publicPerson(Stringname,LocalDatebirthdate){
        this.name=name;
        this.birthdate=birthdate;
      }
    
      publicStringgetName(){
        returnname;
      }
    
      publicLocalDategetBirthdate(){
        returnbirthdate;
      }
    }

    然后,可以继续创建该类的实例

    varperson1=newPerson("John Doe",LocalDate.now());
    varperson2=newPerson("Jane Doe",LocalDate.now());

    JavaScript与Java语法非常相似:

    classPerson{
      constructor(name,birthdate){
        this.name=name;
        this.birthdate=birthdate;
      }
    }
    
    letperson1=newPerson("John Doe",Date.now());
    letperson2=newPerson("Jane Doe",Date.now());

    平行线在那里停止。 得益于JavaScript动态的特性,可以向现有实例添加属性和函数。

    person1.debug=function(){
      console.debug(this);
    }
    
    person1.debug();

    但是,这些仅添加到实例。 其他实例缺少这些补充:

    person2.debug();// Throws TypeError: person2.debug is not a function

    为了向现在和将来的所有实例添加函数(或属性),需要利用原型的概念:

    Person.prototype.debug=function(){
      console.debug(this);
    }
    
    person1.debug();
    person2.debug();
    
    letperson3=newPerson("Nicolas",Date.now());
    
    person3.debug();

    Kotlin:扩展功能/属性

    几年前,我尝试自学Android。 我发现这种体验并不十分适合开发人员:当然,我了解目标之一是尽可能减小占用空间,但这是以非常简洁的API为代价的。

    我记得必须调用带有很多参数的方法,其中大多数为null 我试图找到一种方法来解决这个问题...并发现Kotlin的扩展属性-具有默认参数。 我停止了学习Android的道路,但继续使用Kotlin。

    我爱Kotlin。 许多人赞扬Kotlin的零安全方法。 我喜欢它,但对我来说,最高的价值在于其他地方。

    假设我们经常需要大写字符串。 在Java中实现该目标的方法是使用静态方法创建一个类:

    publicclassStringUtils{
    
      publicstaticStringcapitalize(Stringstring){
        varcharacter=string.substring(0,1).toUpperCase();
        varrest=string.substring(1,string.length()-1).toLowerCase();
        returncharacter+rest;
      }
    }

    在早期,没有一个项目没有StringUtilsDateUtils类。 幸运的是,现在,现有的库提供了最需要的功能, 例如 Apache Commons LangGuava 但是,它们遵循基于静态方法的相同设计原理。 令人遗憾的是,因为Java被认为是一种OOP语言。 不幸的是,静态方法不是面向对象的。

    Kotlin允许在扩展函数和属性的帮助下向现有类分别添加行为。 语法非常简单,并且与面向对象的方法完全兼容:

    funString.capitalize():String{
      valcharacter=substring(0,1).toUpperCase()
      valrest=substring(1,length-1).toLowerCase()
      returncharacter+rest
    }

    在编写Kotlin代码时,我经常使用它。

    在幕后,Kotlin编译器生成的字节码类似于Java代码中的字节码。 它只是“唯一”的语法糖,但是从设计的角度来看,与Java代码相比,这是一个巨大的改进!

    转到:隐式接口实现

    在大多数OOP语言(Java,Scala,Kotlin等)中,类可以遵守合同,也称为接口 这样,客户端代码可以引用该接口,而不关心任何特定的实现。

    publicinterfaceShape{
    
      floatarea();
      floatperimeter();
    
      defaultvoiddisplay(){
        System.out.println(this);
        System.out.println(perimeter());
        System.out.println(area());
      }
    }
    
    publicclassRectangleimplementsShape{
    
      publicfinalfloatwidth;
      publicfinalfloatheight;
    
      publicRectangle(floatwidth,floatheight){
        this.width=width;
        this.height=height;
      }
    
      @Override
      publicfloatarea(){
        returnwidth*height; (1)
      }
    
      @Override
      publicfloatperimeter(){
        return2*width+2*height; (1)
      }
    
      publicstaticvoidmain(String...args){
        varrect=newRectangle(2.0f,3.0f);
        rect.display();
      }
    }
    1. 一个人应该使用BigDecimal来达到精确的目的-但这不是重点

    重要的一点是:由于Rectangle实现Shape ,因此可以在Rectangle任何实例上调用Shape上定义的display()方法。

    Go不是一种OOP语言:它没有类的概念。 它提供结构 ,并且功能可以与这种结构相关联。 它还提供了结构可以实现的接口

    但是,Java实现接口的方法是明确的Rectangle类声明其实现Shape 相反,Go的方法是隐式的 实现接口所有功能的结构隐式实现此接口。

    这将转换为以下代码:

    packagemain
    
    import(
     "fmt"
    )
    
    typeshapeinterface{ (1)
     area()float32
     perimeter()float32
    }
    
    typerectanglestruct{ (2)
     widthfloat32
     heightfloat32
    }
    
    func(rectrectangle)area()float32{ (3)
     returnrect.width*rect.height
    }
    
    func(rectrectangle)perimeter()float32{ (3)
     return2*rect.width+2*rect.height
    }
    
    funcdisplay(shapeshape){ (4)
     fmt.Println(shape)
     fmt.Println(shape.perimeter())
     fmt.Println(shape.area())
    }
    
    funcmain(){
     rect:=rectangle{width:2,height:3}
     display(rect) (5)
    }
    1. 定义shape界面
    2. 定义rectangle结构
    3. 将两个shape函数都添加到rectangle
    4. display()函数仅接受shape
    5. 因为rectangle实现了shape所有功能,并且由于隐式实现,所以rect也是shape 因此,调用display()函数并将rect作为参数传递是完全合法的

    Clojure:“依赖类型”

    我以前的公司在Clojure投入了很多资金。 因此,我尝试学习该语言,甚至写了几篇文章来总结我对语言的理解。

    Clojure在很大程度上受到LISP的启发。 因此,表达式用括号括起来,并且要执行的功能首先位于它们的内部。 另外,Clojure是一种动态类型化的语言:虽然有类型,但没有声明它们。

    一方面,该语言提供了基于合同的编程。 可以指定前置条件和后置条件:在运行时对它们进行评估。 这样的条件可以进行类型检查, 例如,参数是字符串,布尔值等吗? -甚至可以更进一步,类似于_dependent类型

    在计算机科学和逻辑中,从属类型是其定义取决于值的类型。 “整数对”是一种类型。 由于对值的依赖性,“第二对大于第一对的整数对”是从属类型。

    —维基百科
    https://zh.wikipedia.org/wiki/Dependent_type

    它是在运行时强制执行的,因此不能真正称为依赖类型。 但是,这是我所涉猎的语言中最接近的一种。

    之前,我曾详细地写过一个依赖于岗位的类型和基于契约的程序。

    长生不老药:模式匹配

    一些语言自称为提供模式匹配功能。 通常,模式匹配用于评估变量, 例如在Kotlin中:

    varstatusCode:Int
    valerrorMessage=when(statusCode){
      401->"Unauthorized"
      403->"Forbidden"
      500->"Internal Server Error"
      else->"Unrecognized Status Code"
    }

    此用法是类固醇的转换语句。 但是,通常,模式匹配的应用范围更加广泛。 在以下代码段中,将检查第一个常规的HTTP状态错误代码,如果未找到,则默认为更通用的错误消息:

    valerrorMessage=when{
      statusCode==401->"Unauthorized"
      statusCode==403->"Forbidden"
      statusCode-400<100->"Client Error"
      statusCode==500->"Internal Server Error"
      statusCode-500<100->"Server Error"
      else->"Unrecognized Status Code"
    }

    不过,它是有限的。

    Elixir是一种在Erlang OTP上运行的动态类型化语言,将模式匹配提升到了一个全新的水平。 Elixir的模式匹配可用于简单的变量解构:

    {a,b,c}={:hello,"world",42}

    将为a分配:hello ,向b分配“ world”,向c分配42。

    它也可以用于集合的更高级的分解:

    [head|tail]=[1,2,3]

    head将被分配为1,而tail将被分配为[2, 3]

    然而,对于函数重载甚至更是如此。 作为一种功能语言,Elixir没有用于循环的关键字( forwhile ):循环需要使用递归实现。

    例如,让我们使用递归来计算List的大小。 在Java中,这很容易,因为有一个size()方法,但是Elixir API没有提供这种功能。 让我们以Elixir方式伪代码实现它-使用递归。

    publicintlengthOf(List<?>item){
      returnlengthOf(0,items);
    }
    
    privateintlengthOf(intsize,List<?>items){
      if(items.isEmpty()){
        returnsize;
      }else{
        returnlengthOf(size+1,items.remove(0));
      }
    }

    这可以几乎逐行转换为Elixir:

    deflength_of(list),do:length_of(0,list)
    
    defplength_of(size,list)do
      if[]==listdo
        size
      else
        [_|tail]=list (1)
        length_of(size+1,tail)
      end
    end
    1. 模式匹配与可变解构。 头值分配给_变量,这意味着以后无法引用它-因为它没有用。

    但是,如前所述,Elixir模式匹配也适用于函数重载。 因此,写Elixir的名义方法是:

    deflist_len(list),do:list_len(0,list)
    
    defplist_len(size,[]),do:size (1)
    defplist_len(size,list)do (2)
      [_|tail]=list
      list_len(size+1,tail)
    end
    1. 如果列表为空,则调用此函数
    2. 否则调用此函数

    请注意,模式是按照声明的顺序进行评估的:在上面的代码段中,Elixir首先评估具有空列表的函数,并且仅在不匹配的情况下评估第二个函数, 列表不为空。 如果要以相反的顺序声明函数,则每次都会在非空列表上进行匹配。

    Python:理解

    Python是一种动态类型的趋势语言。 就像Java中一样,Python通过for关键字提供循环。 以下片段循环遍历集合中的所有项目,并逐一打印它们。

    fornin[1,2,3,4,5]:
      print(n)

    要收集新集合中的所有项目,可以创建一个空集合,然后将每个项目添加到循环中:

    numbers=[]
    fornin[1,2,3,4,5]:
      numbers.append(n)
    print(numbers)

    但是,可以使用漂亮的Python功能: 进行理解 尽管它与标准循环使用相同的for关键字,但是for comprehension是实现相同结果的功能构造。

    numbers=[nfornin[1,2,3,4,5]]
    print(numbers)

    上一个代码段的输出为[1, 2, 3, 4, 5]

    也可以变换每个项目。 例如,以下代码片段将计算每个项目的平方:

    numbers=[n**2fornin[1,2,3,4,5]]
    print(numbers)

    输出[1, 4, 9, 16, 25]

    理解的好处是可以使用条件句。 例如,以下代码段将仅过滤偶数项,然后将它们平方:

    numbers=[n**2fornin[1,2,3,4,5]ifn%2==0]
    print(numbers)

    输出为[4, 16]

    最后,为了理解,允许使用笛卡尔积。

    numbers=[a:nfornin[1,2,3]forain['a','b']]
    print(numbers)

    将会输出[('a', 1), ('b', 1), ('a', 2), ('b', 2), ('a', 3), ('b', 3)]

    上面的理解也称为列表理解,因为它们旨在创建新列表。 地图理解非常相似,旨在创建...地图。

    结论

    尽管Java是一门不断发展的语言,但这是一件好事。 但是,其他语言中发现的方法也值得研究。 请记住,一种语言构成了人们对问题的思考方式以及解决方案的设计方式。 学习或至少熟悉其他语言是考虑其他观点的好方法。

    翻译自: https://blog.frankel.ch/six-interesting-features-programming-languages/

    c语言 有趣简单编程

    展开全文
  • C语言模块化编程代码示例老赵最近写了一个小代码,是关于C语言程序化编程的,挺有趣的,和大家分享一下啦。一、程序概述二、程序结构三、 具体代码1、主函数2、随机数函数3、产生算法题函数4、答错反馈函数5、答对...

    老赵最近写了一个小代码,是关于C语言程序化编程的,挺有趣的,和大家分享一下啦。

    一、程序概述

    程序的主要功能是随机产生10道数学加减乘除题,用户输入答案,答错或者答对随机给出一句称赞或者鼓励。答对8道题及以上输出分数,否则重新答题。

    二、程序结构

    程序主要分为两大部分:.c代码文件和.h头文件,如下图所示:
    在这里插入图片描述

    三、 具体代码

    1、主函数

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "Question.h"
    
    int main()
    {
        int i,Q;
        int score = 0; //统计答题分数
        for(i=0;i<10;i++)  //循环产生10道题
        {
            Q = Question();
            if(Q)
                score++;
        }
        if(score < 8) //得分少于8分重做
        {
            printf("your score is poor,please try again!\n");
            for(i=0;i<10;i++)  //循环产生10道题
            {
            Q = Question();
            if(Q)
                score++;
            }
        }
        else //得分大于8分,显示分数。
            printf("your score is:%d\n",score);
        return 0;
    }
    
    

    2、随机数函数

    包含随机数函数的头文件,头文件里面只需要写函数声明和宏定义常量。

    //这是Random.c的代码,用“#include "Random.h"”调用头文件的内容
    #include <stdio.h>
    #include <stdlib.h>
    #include "Random.h"
    
    //产生1-10的随机数
    int Random(void)
    {
        int number;
        srand(time(NULL));
        number = (rand()%(MAX_NUMBER -MIN_NUMBER+1)) + MIN_NUMBER;
        return number;
    }
    
    //这是Random.h头文件的内容
    #ifndef RANDOM_H_INCLUDED
    #define RANDOM_H_INCLUDED
    #define MAX_NUMBER 10 //宏常量
    #define MIN_NUMBER 1  //宏常量
    
    int Random(void);//函数声明
    #endif // RANDOM_H_INCLUDED
    

    3、产生算法题函数

    //这是Question.c的代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "Random.h"
    #include "IsError.h"
    #include "IsRight.h"
    #include "Question.h"
    
    
    int Question(void)
    {
        int a,b,i;
        int reply = 0; //学生给出的答案
        int answer=0; //算式的正确答案
        a = Random();
        sleep(1); //让两个随机数生成时间隔1秒,不然短时间内生成的随机数一样
        b = Random();
        i = (rand()%(MAX_NUMBER -MIN_NUMBER+1)) + MIN_NUMBER;//随机产生加减乘除
        switch(i)
        {
            case 1:
                    answer = a+b;
                    printf("%d+%d=?\n",a,b);
                    scanf("%d",&reply);
                    break;
            case 2:
                    answer = a-b;
                    printf("%d-%d=?\n",a,b);
                    scanf("%d",&reply);
                    break;
            case 3:
                    answer = a*b;
                    printf("%d*%d=?\n",a,b);
                    scanf("%d",&reply);
                    break;
            case 4:
                    answer = a/b;
                    printf("%d/%d=?\n",a,b);
                    scanf("%d",&reply);
                    break;
        }
        if(reply == answer)
        {
            IsRight(); //回答正确调用正确评价
            return 1;
        }
        else
        {
            IsError(); //回答错误调用错误评价
            return 0;
        }
    }
    
    //这是Question.h的代码
    #ifndef QUESTION_H_INCLUDED
    #define QUESTION_H_INCLUDED
    #define MAX_NUMBER 4
    #define MIN_NUMBER 1
    
    int Question(void);
    
    #endif // QUESTION_H_INCLUDED
    
    

    4、答错反馈函数

    //这是IsError.c的代码
    #include <stdio.h>
    #include "IsError.h"
    
    void IsError()    //回答错误随机给出下面一句评价
    {
        int i;
        i = (rand()%(MAX_NUMBER -MIN_NUMBER+1)) + MIN_NUMBER;
        switch(i)
        {
            case 1:
                printf("No. Please try again!\n");
                break;
            case 2:
                printf("Wrong.  Try once more!\n");
                break;
            case 3:
                printf("Don’t give up!\n");
                break;
            case 4:
                printf("Not correct. Keep trying!\n");
                break;
        }
    }
    
    //这是IsError.h的代码
    #ifndef ISERROR_H_INCLUDED
    #define ISERROR_H_INCLUDED
    #define MAX_NUMBER 4
    #define MIN_NUMBER 1
    
    void IsError();
    #endif // ISERROR_H_INCLUDED
    

    5、答对反馈函数

    //这是IsRight.c的代码
    #include <stdio.h>
    #include "IsRight.h"
    
    void IsRight()    //回答正确随机给出下面一句评价
    {
        int i;
        i = (rand()%(MAX_NUMBER -MIN_NUMBER+1)) + MIN_NUMBER;
        switch(i)
        {
            case 1:
                printf("Very good!\n");
                break;
            case 2:
                printf("Excellent!\n");
                break;
            case 3:
                printf("Nice work!\n");
                break;
            case 4:
                printf("Keep up the good work!\n");
                break;
        }
    }
    
    //这是IsRight.h的代码
    #ifndef ISRIGHT_H_INCLUDED
    #define ISRIGHT_H_INCLUDED
    #define MAX_NUMBER 4
    #define MIN_NUMBER 1
    
    void IsRight();
    #endif // ISRIGHT_H_INCLUDED
    

    四、运行结果

    在这里插入图片描述

    五、为什么要模块化编程?

    模块化编程的思想是:根据功能将工程划分为不同模块。主函数只调用函数,而不定义函数。在各模块文件中定义功能函数,并将要用到的函数利用同名头文件申明外部函数供其他文件调用。

    使用模块化编程可以使代码更有序,可以便捷地编写大型项目。模块化将不需要的细节尽可能对外部隐藏,实现函数的封装。便于重复利用代码,实现某一功能代码可以在多处调用,可以在别的项目使用。便于分工合作,团队共同开发一个项目,可以将程序分为多个模块,每个人只完成一个模块的内容。

    以上就是本周老赵分享的全部内容,如果你感觉对你有用,欢迎收藏和点赞哦。如果你有什么地方不懂,记得评论区找老赵。咱们大家一起快快乐乐学编程,奥利给!

    展开全文
  • [C] 纯文本查看 复制代码#include #include #include //这是自动关机函数void autoShutdown(){char cmd[20]="shutdown -s -t ";char t[5]="0";char g[10];printf("--------------------------自动关机----------...

    [C] 纯文本查看 复制代码#include

    #include

    #include

    //这是自动的关机的函数

    void autoShutdown(){

    char cmd[20]="shutdown -s -t ";

    char t[5]="0";

    char g[10];

    printf("--------------------------自动关机--------------------------\n");

    printf("你需要在多少秒关机:");

    scanf("%s",t);

    system(strcat(cmd,t));

    printf("你的计算机将在%s秒后关机:\n",t);

    printf("取消关机请输入不关机:");

    scanf("%s",g);

    if(strcmp(g,"不关机")==0){

    system("shutdown -a");

    printf("取消关机成功!\n");

    printf("---------------------------------------------------------\n");

    }

    }

    //这是查询时间的函数

    void nowTime(){

    printf("--------------------------查询时间--------------------------\n");

    int date;

    int time;

    printf("现在的系统时间是:");

    date=system("DATE /T");

    time=system("TIME /T");

    printf("---------------------------------------------------------\n");

    }

    int main(){

    system("COLOR A");

    system("title 小工具");

    int li;

    printf("----------------------------小工具----------------------------\n");

    printf("* *\n");

    printf("* 1、自动关机 2、查询时间 *\n");

    printf("* *\n");

    printf("* *\n");

    printf("* 3、敬请期待 4、敬请期待 *\n");

    printf("* *\n");

    printf("* *\n");

    printf("* tip:输入0退出系统 *\n");

    printf("--------------------------------------------------------------\n");

    while(li!=0){

    printf("\n");

    printf("请输入编号,回车继续:");

    scanf("%d",&li);

    if(li==1){

    autoShutdown();

    }

    if(li==2){

    nowTime();

    }

    if(li==0){

    break;

    }

    else{

    printf("你输入的编号有误,请重新输入!\n");

    }

    }

    printf("按回车键确认退出!\n");

    return 0;

    }

    展开全文
  • 有趣的C语言编程下面讲的是一个关于相亲数对的源程序 首先我先讲一下什么是相亲数对例如num1和num2两个数当num1的真因子数之和所谓真因子数就是出了书本身以外的其他因子数等于num2而num2的真因子数之和等于num1这样...
  • 程序很好玩,学也就好玩多了,一定要先自己编,便不出来在看别人的代码
  • learnc.c 一个有趣的图形演示 pingpong.c 乒乓球 jzq.c 井字棋,我不会玩,你呢? radar.c 一本书上附带的,很眩的动画哦。 russia1.c 俄罗斯方块,不错哦 lights.c 看看你的键盘右边的灯吧,呵呵 russia2.c 简易...
  • 有趣的c语言

    千次阅读 2019-01-29 18:07:38
    写在前面 工作三年多,常听各位前辈讲: ...最近终于有时间,终于还是决定花点时间,把c语言掌握清晰一点,选中了这本已经带领无数大神走向巅峰神书《c专家编程》,打算通读一遍,空口无凭...

    写在前面

    工作三年多,常听各位前辈讲:

    语言是其次的,重要的是思想。

    深以为然,于是继续贯彻陶渊明的:

    好读书,不求甚解。

    结果,工作了三年多,稀里糊涂的代码写了不少,犯的错误也很多,吃一堑长一智的过程中,也会经常有很多不解:“这样写,难道不对么?”

    最近终于有时间,终于还是决定花点时间,把c语言掌握的清晰一点,选中了这本已经带领无数大神走向巅峰的神书《c专家编程》,打算通读一遍,空口无凭,记个笔记,所以,到这里您可以返回了,这,只不过是一个简陋的读书笔记。。。

    01 #define中的空格

    记得最开始学习编程的时候,有听过一些说法,宏定义中的空格实际上没有作用,例如:

    //01-1.1
    #include <stdio.h>    
                                                                                                                                                              
    #define sum(a, b)       ((a) + (b))                                                                                                                                             
    #define sum_1(a, b)     ((a)+(b))                                                                                                                                                                                                                                                                                                                 
    #define sum_2(a,b) ((a)+(b))                                                                                                                                                    
                                                                                                                                                                                    
    int main(int argc, char* argv[])                                                                                                                                                
    {                                                                                                                                                                               
        printf("sum = %d\n", sum(1, 1));                                                                                                                                            
        printf("sum_1 = %d\n", sum_1(1, 1));                                                                                                                                        
        printf("sum_2 = %d\n", sum_2(1, 1));                                                                                                                                        
        return 0;                                                                                                                                                                   
    }          
    

    预编译后的产物,其实是这样的:

    //01-1.2
    //...不相关,省略
    
    int main(int argc, char* argv[])
    {
     printf("sum = %d\n", ((1) + (1)));
     printf("sum_1 = %d\n", ((1)+(1)));
     printf("sum_2 = %d\n", ((1)+(1)));
     return 0;
    }
    

    上面的空格的确不会影响结果输出,而且,行尾多加的几个空格也没有什么用处,然而另外一些情况,显然不是如此:

    //01-2.1.1
    #define a(y) a_expanded(y)
    
    int a_expanded(int y)
    {
            return y + 10;
    }
    
    int main(int argc, char* argv[])
    {
            int x = 100;
    
            a(x);
            return 0;
    }
    

    预编译后如下:

    //01-2.1.2
    //...不相关,省略
    
    int main(int argc, char* argv[])
    {
     int x = 100;
    
     a_expanded(x);
     return 0;
    }
    

    而下面这段代码,加了两个空格之后,含义却完全不同:

    //01-2.2.1
    #define a (y) a_expanded (y)
    
    int a_expanded(int y)
    {
            return y + 10;
    }
    
    int main(int argc, char* argv[])
    {
            int x = 100;
    
            a(x);
            return 0;
    }
    

    预编译后的产物却是这样:

    //01-2.2.2
    //...不相关,省略
    
    int main(int argc, char* argv[])
    {
     int x = 100;
    
     (y) a_expanded (y)(x);
     return 0;
    }
    

    那么显然,空格影响了宏定义的含义,当然,代码01-2.2.1实际上无法执行,因此,宏定义中,显然还是要小心的注意某些位置空格的问题。

    02 const修饰的是谁?

    int foo(const char** p)                                                                                                                                                         
    {                                                                                                                                                                                                                                                                                                                                             
    }                                                                                                                                                                               
                                                                                                                                                                                    
    int main(int argc, char** argv)                                                                                                                                                 
    {                                                                                                                                                                               
        foo(argv);                                                                                                                                                                  
    }                 
    

    上面这段例子里,编译会报warning:

    const.c: In function ‘main’:
    const.c:8:9: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
         foo(argv);
             ^~~~
    const.c:1:5: note: expected ‘const char **’ but argument is of type ‘char **’
     int foo(const char** p)
         ^~~
    

    那么显然,编译器认为,char**并不能直接复制给const char **,会发生隐式类型转换,可是,下面的例子却很常见:

    int foo(const char* p)                                                                                                                                                          
    {         
    }                                                                                                                                                                                
    int main(int argc, char* argv)                                                                                                                                                  
    {                                                                                                                                                                               
        foo(argv);                                                                                                                                                                  
    }                                                                                                                                                                               
    

    那么,一个简单的问题就是,c语言的参数传递实际上是一个赋值过程,那么char*可以赋值给const char*,为什么char **不能赋值给const char**

    两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须包含右边指针所指向类型的全部限定符。

    那么,上面主要有两处需要注意:

    1. 赋值的左右两边必须类型相容。
    2. 左边必须包含右边的全部限定符。

    根据这两个条件,解释以下这个问题:
    char*是一个指向没有限定符char类型的指针。
    const char*是一个有const限定符char类型的指针。
    char类型相容,左边包含右边的限定符,因此可以赋值。

    char**是一个指向char类型的指针的指针。
    const char**是一个指向有const限定符限制的char类型的指针的指针。
    那么显然,二者均没有限定符,且是指针,前者指向char*,后者指向const char*,二者不相容,也因此,char**实际上与const char**不相容,因此,上面的编译会报warning。

    看完上面的例子,并不能让人很容易明白,很多情况下依然是一头雾水,那么,再举个例子,看看const到底修饰的是谁?

    #include <stdio.h>                                                                                                                                                              
                                                                                                                                                                                    
    void test_const_1(void)                                                                                                                                                         
    {                                                                                                                                                                               
        char arr[][10] = {"abc", "def", "hij"};                                                                                                                                     
                                                                                                                                                                                    
        const char *pStr = arr[0];                                                                                                                                                  
        const char *pStr1 = arr[1];                                                                                                                                                 
        const char *pStr2 = arr[2];                                                                                                                                                 
                                                                                                                                                                                    
        const char **ppStr = &pStr;                                                                                                                                                 
        const char **ppStr1 = &pStr1;                                                                                                                                               
                                                                                                                                                                                    
        const char ***pppStr = &ppStr;                                                                                                                                              
                                                                                                                                                                                    
        pStr = pStr1;                                                                                                                                                               
        *pStr = arr[1][1];                                                                                                                                                          
                                                                                                                                                                                    
        ppStr = &pStr1;                                                                                                                                                             
        *ppStr = pStr1;                                                                                                                                                             
        **ppStr = arr[1][1];                                                                                                                                                        
                                                                                                                                                                                    
        pppStr = &ppStr1;                                                                                                                                                           
        *pppStr = &pStr1;                                                                                                                                                           
        **pppStr = pStr1;                                                                                                                                                           
        ***pppStr = arr[1][1];                                                                                                                                                      
    }                                                                                                                                                                               
                                                                                                                                                                                    
    void test_const_2(void)                                                                                                                                                         
    {                                                                                                                                                                               
        char arr[][10] = {"abc", "def", "hij"};                                                                                                                                     
                                                                                                                                                                                    
        const char *pStr = arr[0];                                                                                                                                                  
        const char *pStr1 = arr[1];                                                                                                                                                 
        const char *pStr2 = arr[2];                                                                                                                                                 
                                                                                                                                                                                    
        const char **ppStr = &pStr;                                                                                                                                                 
        const char **ppStr1 = &pStr1;                                                                                                                                               
                                                                                                                                                                                    
        const char ***pppStr1 = NULL;                                                                                                                                               
        char* const **pppStr2 = NULL;                                                                                                                                               
        char** const *pppStr3 = NULL;                                                                                                                                               
                                                                                                                                                                                    
        pppStr1 = &ppStr;                                                                                                                                                           
        *pppStr1 = &pStr1;                                                                                                                                                          
        **pppStr1 = pStr1;                                                                                                                                                          
        ***pppStr1 = arr[1][1];                                                                                                                                                     
        
        /*!
         * 错误用法,赋值表达式左边不包含右边的全部限定                                                                                                                             
         * ppStr中const修饰char,表示不能通过**ppStr修改char的值                                                                                                                    
         * pppStr2中const修饰char *,表示不能通过**pppStr2修改char* 的指向
         */
        //pppStr2 = &ppStr;
        /*!
         * 错误用法,赋值表达式左边不包含右边的全部限定
         * pStr1中const修饰char,表示不能通过*pStr1修改char的值
         * pppStr2中const修饰char *,表示不能通过**pppStr2修改char* 的指向
         */
        //*pppStr2 = &pStr1;//! 隐式类型转换
        **pppStr2 = pStr1;
        ***pppStr2 = arr[1][1];
        
        /*!
         * 错误用法,赋值表达式左边不包含右边的全部限定
         * ppStr中const修饰char,表示不能通过**ppStr修改char的值
         * pppStr3中const修饰char**,表示不能通过*pppStr3修改char** 的指向
         */
        //pppStr3 = &ppStr;
        *pppStr3 = &pStr1;
        /*!
         * 错误用法,赋值表达式左边不包含右边的全部限定
         * pStr1中const修饰char,表示不能通过*pStr1修改char的值
         * pppStr3中const修饰char**,表示不能通过*pppStr3修改char** 的指向
         */
        //**pppStr3 = pStr1;
        ***pppStr3 = arr[1][1];
    }   
    
    int main(int argc, char* argv[])
    {
        test_const_1();
    
        test_const_2();
    
        return 0;
    }
    

    猜猜看,上面哪些内容会编译报错?

    const.c: In function ‘test_const_1’:
    const.c:17:8: error: assignment of read-only location ‘*pStr’
      *pStr = arr[1][1];
            ^
    const.c:21:10: error: assignment of read-only location ‘**ppStr’
      **ppStr = arr[1][1];
              ^
    const.c:26:12: error: assignment of read-only location ‘***pppStr’
      ***pppStr = arr[1][1];
                ^
    const.c: In function ‘test_const_2’:
    const.c:47:13: error: assignment of read-only location ‘***pppStr1’
      ***pppStr1 = arr[1][1];
                 ^
    const.c:61:12: error: assignment of read-only location ‘**pppStr2’
      **pppStr2 = pStr1;
                ^
    const.c:70:11: error: assignment of read-only location ‘*pppStr3’
      *pppStr3 = &pStr1;
               ^
    

    经过上面的例子,可以简单的记忆为,const修饰的指针变量中,去掉数据类型,const后面的变量不可直接修改,例如char** const *pppStr3*pppStr3不可以直接赋值修改。

    展开全文
  • 下面我们看一些有趣的C语言代码。 Exp: main(){ printf(&unix["\021%six\012\0"], (unix)["have"] + "fun" - 0x60);} 第一步: 对于这样的代码要理解首先要做的是进行缩排,缩排后...
  • 有趣的C语言】空瓶换汽水问题

    千次阅读 2018-04-27 13:34:40
    有趣的C语言  相信大家学习C语言的过程中都做过这么一道题: 喝汽水,1瓶汽水1元,两个空瓶可以换一瓶汽水,给20元,可以喝多少瓶汽水。编程实现。  那么这道题在C语言中应该如何实现呢?  下面是我写的...
  • 有趣的氛围中看代码,让自己的动手能力得到加强。 rar文档
  • C语言实例解析精粹源代码

    热门讨论 2009-09-20 03:39:01
    095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 ...
  • 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式...
  • C语言编程的方法来实现我们在生活中经常玩到一个猜数字小游戏(1到100数字),其主要玩法就是我们编写出一个程序,起先计算机会先自动生成一个数,这个数也就是我们需要去才对数,然后玩家在这个程序执行...
  • C语言代码实例.rar

    2009-08-27 20:17:58
    095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 ...
  • 这应该允许更快的编程,更快的调试,更少的代码行以及C的所有功能。 海-C,只是用不同的方式写。 发音 虽然这个玩词游戏很有趣,但我不想创建“ gif”情况。 .sea文件扩展名的发音类似于英语单词“ sea”。 .hea...
  • 《妙趣横生的算法(C语言实现)》理论与实践相结合,旨在帮助读者理解算法,并提高C语言编程能力,培养读者的编程兴趣,并巩固已有的C语言知识。全书分为2个部分共10章,内容涵盖了编程必备的基础知识(如数据结构、...
  • 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 ...
  • 《妙趣横生的算法(C语言实现)》理论与实践相结合,旨在帮助读者理解算法,并提高C语言编程能力,培养读者的编程兴趣,并巩固已有的C语言知识。全书分为2个部分共10章,内容涵盖了编程必备的基础知识(如数据结构、...
  • 在大多数计算机编程语言中,while循环是一个控制流语句,该语句允许根据给定的布尔条件重复执行代码。布尔条件为true或false while(1) 这是一个无限循环,它将一直运行到显式发出break语句为止。有趣的是,...
  • 初识c语言

    2021-03-03 21:55:19
    本人大一,寒假期间在b站自学c语言教程,已初步了解c语言并初步学习了有关内容,能写出一些简单的代码,觉得编程有趣,希望未来能成为一个程序员,在这里做一个总结。 首先我安装了编译器VS2019,之后学习了计算机...
  • 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 ...
  • 利用c语言代码打印一个心形(带立体感)

    万次阅读 多人点赞 2016-01-26 17:16:26
    在我们IT行业每天面对的就是敲代码,所以很多人无法接受这份工作,因为很无聊也很枯燥,长期工作会使人情绪低落,其实我们编程很多时候也有有趣的地方,接下来我就用一个简单的c语言作图来缓解一下气氛。 源程序: ...
  • 第一个C语言小游戏

    千次阅读 多人点赞 2020-11-29 22:07:34
    大家好,我是一位大一小白,之前并没有想到我会和编程打交道,接触C语言后,我才发现C语言如此有趣,今天,我终于成功完成第一个C语言小游戏------石头剪刀布。虽然代码简单,没有什么技术含量,但是希望各位大佬...
  • 书中除了讲解C程序设计语言,还广泛介绍了作为一名C程序设计人员应该掌握的必要知识,并提供了大量的实用性很强的编程实例。本书的目标是使你在C语言程序设计方面由一位初学者成为一位称职的程序员。读者基本不需要...
  • 有趣的游戏编程,让你也能编一个属于你自己的游戏,呵呵,让别人羡慕你吧
  • 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 ...
  • (1) 授课方式采用语法讲解+内存布局示意图+项目方式,让课程生动有趣好理解 (2) 系统全面讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二...
  • C语言实例解析精粹(第二版) 光盘代码 本文件包括以下内容: ※ 1、文件说明 ※ 2、源码操作说明 ※ 3、光盘目录清单 ◎ 源码操作说明 源代码使用方法是(以实例1为例): 将该实例源码,比如实例11.c文件(可以...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 153
精华内容 61
关键字:

c语言有趣的编程代码

c语言 订阅