一、C语言基本框架
#include<stdio.h>
int main()
{
//代码主体
return 0;
}
注意看以上代码,这就是C语言代码框架,任何代码都要包含以上框架。
其中,#include<stdio.h>的作用是包含了一个标准输入输出(Standard input&output,即stdio.h),它定义了之后的printf函数和scanf函数等执行输入操作和输出操作的函数。
二、Hello World!
在屏幕上输出一段话(Hello World!),代码如下:
#include<stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
其运行结果如下:
Hello World!
printf函数的功能就是在屏幕上输出内容,输出的内容取决于英文括号里面的内容。
三、变量和常量
变量,就是计算机程序运行过程当中可以被改变的量;常量就是程序运行当中不可被改变的量。
C语言中必须对变量定义一个类型,在这之后这个变量就只能是这个类型。
C语言中变量的类型有整型、浮点型、字符型,其中整型分为短整型(short int或short)、整型(int)、长整型(long int或long)和长长整型(long long int或long long),浮点型分为单精度浮点型(float)和双精度浮点型(double),字符型只有一种(char),整型还可以分为有符号整形和无符号整型,一般默认为有符号整型,无符号整型需要在每个类型的前面加上unsigned即可,例如无符号长整型为unsigned long int或者unsigned long。
常量就是不可被改变的量,例如0,1,2,3……当然,C语言中有一个定义常量的方式,即const。
const int a=1;
上面这行代码的意思是定义一个整型常量a,然后初始化为1,之后这个常量就不可再被改变。即在这个函数内部,a只能是1
变量的初始化
C语言中,使用变量时一定要对变量进行定义。如果没有定义变量,则会出现以下报错
[Error] 'a' was undeclared in this scope
这个报错的意思是,a在这个函数中没有被声明。也就是说,编译器不知道a是个什么东西。总之。没有定义变量类型的话,编译器不知道怎么将一个值存到a里面去。
这个报错的源代码如下
#include<stdio.h>
int main()
{
a=1;
return 0;
}
因为a没有定义类型,所以如果将它定义为int类型的话,那么存入到a里面的就会是00000000 00000000 00000000 00000001(4个字节),而如果定义为short类型的话,就是00000000 00000001(2个字节)。
所以,正确的做法应该是
#include<stdio.h>
int main()
{
int a;
a=1;
return 0;
}
或
#include<stdio.h>
int main()
{
int a=1;
return 0;
}
这样的话,因为编译器知道a是int类型,所以会分配4个字节,然后就能通过了。
变量的修改
接下来看这样一段代码
#include<stdio.h>
int main()
{
int a=1;
a=2;
printf("%d",a);
return 0;
}
思考:这段代码的运行结果会是什么呢?
A. 1 B. 2 C. 钝角
答案选B
为什么呢?
因为我们的程序是从上往下一行一行执行的,所以在第4行的时候,我们对变量a进行初始化为1,然后在第5行改变了a的值,让a的值为2。此时,我们在输出a的时候,a的值就变为2了。
四、标准输入和标准输出
标准输入函数(scanf)
scanf函数的原型如下
int scanf(const char *format, ...);
在实际运用当中,scanf函数的作用就是从键盘读入一个值,并将这个值存入计算机中。
示例如下
#include<stdio.h>
int main()
{
int a;
scanf("%d",&a);
return 0;
}
当然,这段代码不会有任何输出,实际运用中会搭配printf来使用。
上面这段代码中a的值取决于你在键盘上输入的数字。例如,键入2,回车之后,a的值就是2了。此时,如果在scanf后面加上一个printf("%d",a);的话,就会输出2了。
需要注意的是,scanf后面的参数需要加上一个&符号,其作用在后面的《地址》这一章会讲到。
并且,如果scanf的参数不加&,写成scanf("%d",a);的话,编译器也不会报错,但是运行会出错。
标准输出函数(printf)
printf函数的原型如下
int printf(const char *format, ...)
在实际运用当中,printf函数的作用是在屏幕中输出内容,用法如下
#include<stdio.h>
int main()
{
int a=1;
printf("%d",a);
return 0;
}
这段代码的输出为1。
%d、%f和%c
前面我们讲到printf和scanf的用法,其中有个%d,这个的作用其实就是把逗号后面的值传进来。
其对应关系如下表所示:
占位符 | 定义类型 | 数据类型 |
%d | int | 整型 |
%hd | short或short int | 短整型 |
%ld | long或long int | 长整型 |
%f | float | 单精度浮点型 |
%lf | double | 双精度浮点型 |
%c | char | 字符型 |
%p | 地址 |
在实际运用中,通常会遇到需要传递多个参数的情况,以printf为例
printf("a=%d,b=%d",a,b);
前面出现了两个占位符,第一个占位符所对应的就是第一个参数a,第二个占位符所对应的就是第二个参数b。
scanf同理,不过scanf在参数前面要加上&。
需要注意的是,占位符的数量必须和参数的数量相同,否则无法通过编译(报错)。
%、\和"的输出
特别的,如果要输出百分号(%)、反斜杠(\)、英文双引号(")等具有特殊意义的字符,就需要在前面加上点什么东西。
例如,想要输出%的话,错误示例如下
#include<stdio.h>
int main()
{
printf("%");
return 0;
}
这样不行的原因是,百分号作为占位符,具有特殊含义,编译器不知道你是想把百分号作为一个字符输出还是想作为占位符传入参数后输出。
正确示例如下
#include<stdio.h>
int main()
{
printf("%%");
return 0;
}
由上可知,若想要输出一个百分号,则需要在该处打两个百分号输出。
同理可知,如果想要输出一个反斜杠(\),则需要打两个反斜杠;输出英文双引号("),则需要在前面加上一个反斜杠作为转义字符输出,即
#include<stdio.h>
int main()
{
printf("\"");
return 0;
}
五、选择控制结构
在程序设计中,通常会遇到以下情况
如果符合某个条件,就执行某条语句;反之则不执行
如果符合某个条件,就执行某条语句;反之则执行另一条语句
如果符合某个条件,就执行某条语句;反之则继续判断条件2是否成立,成立则执行语句2,不成立则执行语句3
……
例如:已知一分段函数f(x),求该分段函数的值。
此时,可以编写程序输入x的值,程序自动输出函数f(x)的值。
代码如下所示
#include<stdio.h>
int main()
{
int x;
scanf("%d",&x);
if(x>=0&&x<=2)
printf("%d",x);
else if(x>2&&x<=5)
printf("%d",3*x);
else if(X>5&&x<=10)
printf("%d",x*x);
else
printf("Invalid number!");
return 0;
}
由上可知,if的用法为
if(判断表达式)
执行语句;
说人话就是如果判断表达式成立,就执行下面的语句。
if else的用法为
if(条件表达式)
执行语句1;
else
执行语句2;
说人话就是如果条件表达式成立就执行语句1,否则就执行语句2。
if else-if else的用法为
if(条件表达式1)
执行语句1;
else if(条件表达式2)
执行语句2;
else
执行语句3;
说人话就是如果条件表达式1成立就执行语句1,如果不成立就判断条件表达式2是否成立,成立就执行语句2,不成立就执行语句3。
除if else之外,C语言还存在着另一种选择控制结构switch case。
下面来看一段代码
#include<stdio.h>
int main()
{
int a;
scanf("%d",&a);
switch(a)
{
case 1: printf("One");
break;
case 2: printf("Two");
break;
case 3: printf("Three");
break;
default: printf("Others");
break;
}
return 0;
}
这段代码的功能是,输入一个数,如果这个数是1的话,就输出One;2的话就输出Two;3的话就输出Three;如果是其他的数的话就输出Others。
需要注意的是,switch case语句中case的功能是程序输出的入口。这就是说,如果没有break语句退出switch语句的话,那么case对应的语句以及后面的语句都会被执行,例如:
#include<stdio.h>
int main()
{
int a=1;
switch(a)
{
case 1: printf("One\n");
case 2: printf("Two\n");
case 3: printf("Three\n");
default: printf("Others\n);
}
return 0;
}
该代码的执行结果如下
One
Two
Three
Others
如果将第4行的int a=1改为int a=2,那么就会是
Two
Three
Others
switch case语句相较于if else语句而言的优点就是switch case语句运行起来会比if else要快,特别是在if else分支较多的时候。不过,现在的计算机性能已经很强了,一秒钟可以运行几千万次if else语句,所以这个优点也没什么了。而且,if else语句对于程序员们来说较于switch case来说易于维护,所以我们通常倾向于使用if else语句而非switch case语句。
六、循环控制结构
当我们需要进行很多个数求和的时候,定义多个变量进行求和明显是低效率的,因此我们需要用到一种方法来进行高效率的运行。
例如,求1+2+3+…+100的值。
#include<stdio.h>
int main()
{
int i,sum=0;
for(i=1;i<=100;i++)
{
sum+=i;
}
printf("%d",sum);
return 0;
}
这段代码的输出结果为
5050
接下来,我们对这段代码进行逐行解读。
在第4行,定义了一个整型变量i和sum,并将sum初始化为0;
在第5行,用for循环遍历i从1到100,然后将sum累加至i里面,最后输出sum的值。
下面讲讲C语言语法中的几个循环
while循环
while循环的结构如下
while(判断语句)
{
执行语句;
}
其中,当判断语句成立(即判断语句的值为非0)的时候,执行循环体内的执行语句,然后再判断语句是否成立,如果成立,再执行一遍循环体内的语句,直到判断语句不成立为止。
例如
#include<stdio.h>
int main()
{
int i=1;
while(i<5)
{
printf("%d\n",i);
i++;
}
return 0;
}
这段代码设定了i的初始值为1,然后判断i的值是否小于5,1<5成立,输出当前i的值1,然后i自增,2<5成立,输出当前i的值2,……
结果如下:
1
2
3
4
不过,while循环有一个缺点,那就是当初始条件不满足的情况下,while循环就一次都不执行。那么为了解决这一问题,C语言有一个do-while循环。
do-while循环
do-while循环的结构如下
do
{
执行语句;
}while(判断语句);
do-while循环与while循环的唯一区别就是do-while循环是先执行循环体再判断条件,而while循环是先判断条件再执行语句,因此,do-while循环至少会执行一次,在某些你想要至少执行一次的程序里,最好还是使用do-while循环。
for循环
相比于while循环,for循环更难以理解,但是在程序设计中,for循环却是最为简洁的循环格式,也是在实际运用当中最常用的。因此,掌握for循环十分重要。
for循环的格式如下
for(初始表达式;判断表达式;循环表达式)
{
执行语句;
}
在for循环中,初始表达式只执行一次,然后每次循环开始前判断表达式是否成立,直到判断表达式不成立终止循环,每次循环结束前执行一次循环表达式,并且每个for循环都可以写成while循环,便于理解。
设有一个for循环
for(A;B;C)
{
D;
}
与之对应的while循环如下
A;
while(B)
{
D;
C;
}
七、指针与地址
我们知道,计算机要存储一个数值,必须要将这个数值存储在内存中。而要调用这个数据,则需要将这个数据在内存当中找到,就像我们在图书馆中找到你想要的书籍一样,或者查字典一样。那么计算机在调用这个数据是怎么调用的呢?计算机是怎么找到这个数据的呢?这就是地址。
定义一个指针变量
int *p;
那么这个*p就是所谓的指针变量,指针变量本质上还是一个变量,只不过这个指针变量存放的是内存地址。内存地址就是给计算机提供访问位置的地址,就像我去你家需要你家的地址,计算机访问数据的时候也需要一个地址进行访问变量。
指针变量的操作
int a = 10;
int *p = &a; //通过指针变量访问变量a
printf("%d\n",*p);
printf("%d\n",a);
/* 以上两个为等价形式 */
int *p = 20; //通过指针变量修改变量a的值
printf("%d\n",a);