C语言学习笔记

第一章 导言

1.1 入门

学习一门新的程序设计语言的唯一途径就是使用它编写程序。对于所有语言的初学者来说,编写的第一个程序几乎都是相同的,即;

打印出以下内容

hello, world

尽管这个练习很简单,但对于初学语言的人来说,它仍然可能成为一大障碍,因为要实现这个目的,我们首先编写程序文本,然后成功地进行编译,并加载、运行,最后输出到某个地方。掌握了这些操作细节后,其他事情就比较容易了。

#include <stdio.h>        //包含标准库的信息

main()                    //定义名为main的函数,它不接受参数值
{                         //main函数的语句都被括在花括号中
    printf("hello, world\n");     //main函数调用库函数printf以显示字符序列
}                                 // \n代表换行符

在Linux系统中,输入 gcc hello.c && ./a.out

编译、加载、运行

1.2 变量与算术表达式

来看下一个程序,使用公式 C=(5/9) (F-32) 打印下列华式温度与摄氏温度对照表:

0  -17

20 -6

40 4 

60 15

80 26

100 37

120 48

140 60

160 71

180 82

200 93

220 104

240 115

260 126

此程序中仍然只包括一个名叫main的 函数定义。它比前面的hello.c 的程序长一些,但并并不复杂。这个程序中引入了一些新的概念,包括注释、声明、变量、算术表达式、循环以及格式化输出。

#include <stdio.h>
/*  当fahr= 0, 20, ..., 300时,分别打印华氏温度与摄氏温度对照表 */
main()
{
    int fahr, celsius;
    int lower, upper, step;

    lower = 0;    //温度表的下限
    upper = 300;    //温度表的上限
    step = 20;    //步长
    
    fahr = lower;
    while (fahr <= upper)
{
    celsius = 5 * (fahr-32) / 9;
    printf("%d\t%d\n", fahr, celsius);
    fahr = fahr + step;
  
    }
}

/* 与*/之间的字符序列将被编译器忽略。注释可以自由的运用在程序中,使得程序更易于理解。程序中允许出现空格、制表符或换行符之处,都可以使用注释

在C语言中所有变量都必须先声明后使用。声明通常放在函数起始处,在任何可执行语句之前。声明用于说明变量的属性,它由一个类型名和一个变量表组成,例如:

int fahr,celsius;

int lower,upper,step;

其中int 表示后所列变量为整数,与相对应的,float表示所列变量为浮点数。int 与float 类型的取值范围取决于具体的机器。对于int类型通常为16位,其范围在-32768~+32767之间,也有用32位表示的int类型。float通常为32位,其至少有6位有效数字。

C语言还提供了其他一些基本数据类型:

char          字符---一个字节

short         短整型

long          长整型

double       双精度浮点型

这些数据类型对象的大小也取决于具体的机器。还存在这些基本数据类型的数组、结构、联合,指向这些类型的指针以及返回这些类型值的函数。我们将在后续响应的章节中分别介绍。

在上面的温度转换程序中,最开始计算是下列4个赋值语句:
lower = 0;

upper = 300;

step = 20;

fahr = lower;

它们为变量设置初值。各条语句均以分号结束。

温度转换表中的各行计算方式相同,因此可以用循环语句重复输出各行。这是while循环语句的用途:

while (fahr <= upper){

...

}

while 循环语句是这样的:首先测试圆括号中的条件,如果条件为真(fahr <= upper)则执行循环体(括在花括号中的3条语句)

然后再重新测试圆括号中的条件,如果为真,则再次执行循环体,当圆括号中的条件测试结果为假(fahr > upper)时循环结束,并继续执行跟在while循环语句之后的下一条语句。

在该程序中,绝大部分工作都是在循环体中完成的。循环体中的赋值语句

celsius = 5 * (fahr - 32 ) / 9;

用于计算与指定华氏问对相对应的摄氏温度值,并将结果赋值给变量celsius

printf是一个通用输出格式化函数,其中的每个百分号表示其他的参数之一进行替换的位置,并指定打印格式例如%d指定一个整型参数

(\t)一个制表符的空间

格式说明可以省略宽度与精度。例如:%6f表示待打印的浮点数至少有6个字符宽   %.2f指定待打印的浮点数的小数点后有两位小数,但宽度没有限制   %f则仅仅要求按照浮点数打印该数。

%d          按照十进制整型数打印

%6d        按照十进制整数型打印,至少6个字符宽

%f           按照浮点数打印

%6f         按照浮点数打印,至少6个字符宽

%.2f        按照浮点数打印,小数点后有两位小数

%6.2f      按照浮点数打印,至少6个字符宽,小数点后有两位小数

1.3for 语句

对于某个特定任务我们可以采用多种方法来编写程序。下面这段代码也可以实现前面的温度转换程序的功能

#include <stdio.h>


main()

{
    int fahr;
    
    for (fahr = 0; fahr <= 300; fahr = fahr + 20)
        printf ("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));

}

for 语句是一种循环语句,它是对while 语句的推广。如果将for语句与前面介绍的while语句比较,就会发现for语句的操作更直观一些。

fahr=0          是初始化部分,仅在进入循环前执行一次。

fahr <=300   是控制循环的测试或条件部分。循环控制将对该条件求值,如果结果为真(true)则执行循环体

fahr = fahr + 20 以将循环变量fahr 增加一个步长,并再次对条件求值。如果计算的到的条件值为假循环将终止执行。与while语句一样,for循环语句的循环体可以只有一条语句,也可以是用花括起来的一组语句。

1.4符号常量

#define指令可以把符号名定义为一个特定的字符串

#define 名字 替换文本

在该定义之后,程序中出现的所有在#define中定义的名字,都将用相应的替换文本替换。其中,名字与普通变量名的形式相同:他们都是以字母打头的字母和数字序列;替换文本可以是任何字符序列,而不仅限于数字。

符号常量通常是大写字母,这样可以很容易与用小写字母拼写的变量名相区别。注意#define指令行的末尾没有分号

1.5字符输入/输入

标准库提供的输入/输出模型非常简单。无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理。文本流是由多行字符构成的字符序列,而每行字符则由0个或多个字符组成,行末是一个换行符。

标准库提供了一次读/写一个字符的函数,其中最简单的是getchar和putchar两个函数。每次调用时,getchar函数从文本流中读入下一个输入字符,并将其作为结果值返回。

1.5.1 文件复制

借助于getchar与putchar函数,可以在不了解其他输入/输出知识的情况下编写出数量惊人的有用的代码。最简单的例子就是把输入一次一个字符的复制到输出,其基本思想如下

#include <stdio.h>

main()
{
    int c;
    c = getchar();
    while (c != EOF) {
        putchar(c);
        c = getchar();
    }
}

其中,关系运算符 !=表示 “不等于”

字符在键盘、屏幕或其他的任何地方无论以什么形式表现,它在机器内部都是以位模式存储的。char类型专门用于存储这种字符型数据,当然任何整型(int)也可以用于存储字符型数据。因为某些潜在的重要原因,我们在此使用int类型

1.5.2 字符计数

下列程序对于字符进行计数,它与上面的复制程序类似。

#include <stdio.h>

main ()
{
    long nc;
    
    nc = 0;
    while (getchar() != EOF)
        ++nc;
    printf("%ld\n", nc);
}

其中,语句

++nc;

引入了一个新的运算符++,其功能是执行加1操作。可以用语句nc=nc+1代替它,但语句++nc更精炼一些,且通常效率更高。

与该运算符响应的是自减运算符--。++与--这两个运算符既可以作为前缀运算符也可以作为后缀运算符。

1.5.3 行计数

统计行计数等价于统计换行符的个数。

#include <stdio.h>

main()
{
    int c, nl;
       
    nl = 0;
    while ((c = getchar() ) ! = EOF)
        if(c == '\n' )
            ++nl;
    printf("%d\n", nl);
    
}

在该程序中,while循环语句的循环体是一个if语句, 他控制自增语句++nl。if语句先测试圆括号中的条件,如果该条件为真,则执行其后的语句。这里再次用缩进方式表明语句之间的控制关系。

双等于号==是c语言中表示“等于”关系的运算符(类似于pascal中的单等于号=及fortran中的.EQ)由于C语言将单等于号作为复制运算符,因此使用双等于号==表示相等的逻辑关系,以示区分。

1.5.4 单词计数

用于统计行数、单词数与字符数。这里对单词的定义比较宽松,它是任何其他不包含空格、制表符或换行符的字符序列。

#include <stdio.h>

#define IN 1
#define OUT 0

main()
{
    int c, nl, nw, nc, state;
    
    state = OUT;
    nl = nw = nc = 0;
    while ((c = getchar()) !=EOF){
    ++nc;
    if (c == '\n')
        ++nl;
    if (c == '' || c =='\n' || c =='\t')
        state = OUT;
    else if (state == OUT)    {
    state = IN;
    ++nw;
    }
}
      printf("%d %d %d\n", nl, nw, nc);
}

程序执行时,每当遇到单词的第一个字符,它就作为一个新单词加以统计。state变量记录程序当前是否正位于一个单词之中,它的初值是“不在单词中”,即初值被赋为OUT。

1.6 数组

编写一个程序,以统计各个数字、空白符以及所有其他字符出现的次数。这个程序的实用意义并不大,但我们可以通过该程序讨论C语言多方面的问题。

#include <stdio.h>

main ()
{
    int c, i, nwhite, nother;
    int ndigit[10];

    nwhite = nother =0;
    for (i = 0; i < 10; ++i)
        ndigit[i] = 0;

    while((c = getchar()) != EOF)
        if(c >= '0' && c <='9')
            ++ndigit[c-'0'];
        else if (c == '' || c == '\n' || c == '\t')
            ++nwhite;
        else
            ++nother;

    printf("digits =")
    for (i = 0; i < 10; ++i)
    
        printf("%d", ndigit[i]);
    printf(", white space = %d, other = %d\n",
        nwhite, nother);

    
}

1.7 函数

到目前为止,我们所使用的函数(如printf、getchar和putchar)都是函数库中提供的函数,现在让我们

编写函数。现在编写一个求幂的函数power(m,n)来说明函数定义的方法。用于计算整数m的n次幂,其中n是正整数。对函数调用

power(2,5)来说,结果为32。

#include <stdio.h>

int power (int m, int n);

main()
{
    int i;
    
    for (i = 0; i < 10; ++i)
        printf("%d %d %d\n", i, power(2,i), power(-3,i));
        return 0;
}

int power(int base, int n)

{
    int i, p;

    p = 1;
    for (i = 1; i <= n; ++i)
        p = p * base;
    return p;
}

函数定义可以以任意次序出现在一个源文件或多个源文件中,但同一函数不能分割存放在多个文件中。每次调用时,main函数返回一个格式化的整数并打印。在表达式中,power(2,i)同2和i一样都是整数。

1.8 参数——传值调用

  传值调用的利大于弊。在被调用函数中,参数可以看作时便于初始化的局部变量,因此额外使用的变量更少,这样程序可以更紧凑简洁。

1.9  字符数组

用来存放字符的数组称为字符数组,例如:

  1. char a[10]; //一维字符数组
  2. char b[5][10]; //二维字符数组
  3. char c[20]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a','m'}; // 给部分数组元素赋值
  4. char d[]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm' }; //对全体元素赋值时可以省去长度

字符数组实际上是一系列字符的集合,也就是字符串(String)。在C语言中,没有专门的字符串变量,没有string类型,通常就用一个字符数组来存放一个字符串。

1.10 外部变量与作用域

  • 局部变量(内部变量):在定义它的函数内有效,但是函数返回后失效;
  • 全局变量(外部变量):在所有源文件内均有效。在同源文件的函数中使用使用全局变量,需要将全局变量提前声明;同时在不包含全局变量定义的不同源文件需要用extern关键字再次声明

如果在该函数内定义了一个与之前定义的全局变量同名的变量,那么该同名局部变量就会在函数内部屏蔽全局变量的影响。即当局部变量与全局变量同名时,在局部变量的作用范围之内,全局变量不起作用。局部变量优先原则;
全局变量是有默认值的(引用类型的变量默认值都是null,基本类型的变量默认值则不一样,int型变量默认值是0),但是局部变量没有默认值;
全局变量可以在函数外定义并初始化,但不能进行赋值操作。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值