Chinaunix首页 | 论坛 | 博客
  • 博客访问: 112147
  • 博文数量: 28
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 202
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-31 21:51
个人简介

諸惡莫做,眾善奉行,自淨其意!

文章分类

全部博文(28)

文章存档

2018年(1)

2017年(3)

2015年(3)

2014年(21)

我的朋友

分类: C/C++

2017-02-12 11:33:18

本博文主要是根据上关于C快速入门的内容整理汇总而成


先从一个简单的C语言程序简单分析C语言程序

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main()
  3. {
  4.     puts("C语言中文网");
  5.     return 0;
  6. }

第一行是头文件,C语言开发者们编写了很多常用函数,并分门别类的放在了不同的文件,这些文件就称为头文件(header file)类似python语言的中包。较早的C语言标准库包含了15个头文件
第二,四行是是函数,在C语言中,有的语句使用时不能带括号,有的语句必须带括号。带括号的称为函数(Function)C语言自带的函数称为库函数(Library Function),如puts()自己编写的函数称为自定义函数, 如第2-6行代码就是该类。C语言规定,一个程序必须有且只有一个 main 函数。main 被称为主函数,是程序的入口函数,程序运行时从 main 函数开始,直到 main 函数结束(遇到 return 或者执行到函数末尾时,函数才结束)。

C语言中的空白符

空格、制表符、换行符统称为空白符,它们只能占位,没有实际的内容。

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. int main()
  3. {
  4.     puts
  5.     ("C语言中文网");
  6.    
  7.     puts
  8.     (
  9.     "C语言中文网"
  10.     )
  11.     ;
  12.    
  13.     puts ("C语言中文网");

  14.     puts ( "C语言中文网" ) ;

  15.     return 0;
  16. }

上面的输出结构都是一样的,需要注意的是:字符串中的空格和制表符不会被忽略,它们会被输出到控制台上。

变量和数据类型转换

点击(此处)折叠或打开

  1. int a=123;
  2. a=1000;
  3. a=9999

不同于python,C语言中的变量定义必须说明变量的类型,如int表示真是类型。数据是放在内存中的,变量是给这块内存起的名字,有了变量就可以找到并使用这份数据。第一行的意思是在内存中找一块区域,命名为a,用它来存放整数,同时赋值给a。
    在C语言中,有多种数据类型,例如:

说  明 字符型 短整型 整型 长整型 单精度浮点型 双精度浮点型 无类型
数据类型 char short int long float double void

数据类型转换的一般格式为:

(type_name) expression


点击(此处)折叠或打开

  1. (float) a; //把a转换为实型
  2. (int)(x+y); //把x+y的结果转换为整型
  3. (float) 100; //将一个常量转换为实型

C语言自增(++)和自减(--)

值得注意的是,++ 在变量前面和后面是有区别的:


  • ++ 在前面叫做前自增(例如 ++a)。前自增先进行自增操作,再进行其他操作。
  • ++ 在后面叫做后自增(例如 a++)。后自增先进行其他操作,再进行自增操作。
自减(--)也一样,有前自减和后自减之分。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5.     int a=10, a1=++a;
  6.     int b=20, b1=b++;
  7.     int c=30, c1=--c;
  8.     int d=40, d1=d--;
  9.     printf("a=%d, a1=%d\n", a, a1);
  10.     printf("b=%d, b1=%d\n", b, b1);
  11.     printf("c=%d, c1=%d\n", c, c1);
  12.     printf("d=%d, d1=%d\n", d, d1);
  13.     system("pause");
  14.     return 0;
  15. }
输出结果:
a=11, a1=11
b=21, b1=20
c=29, c1=29
d=39, d1=40


标识符、关键字和注释    

    定义变量时,我们使用了诸如“a”“abc”“mn123”这样的名字,它们都是程序员自己起的,一般能够表达出变量的作用,这叫做标识符(Identifier)C语言规定,标识符只能由字母(A~Z, a~z)、数字(0~9)和下划线(_)组成,并且第一个字符必须是字母或下划线。
    关键字(Keywords)是由C语言规定的具有特定意义的字符串,通常也称为保留字,例如 int、char、long、float、unsigned 等。我们定义的标识符不能与关键字相同,否则会出现错误。
    注释(Comments)可以出现在代码中的任何位置,用来向用户提示或解释程度的意义。程序编译时,会忽略注释,不做任何处理,就好像它不存在一样。
C语言支持单行注释和多行注释:

  • 单行注释以//开头,直到本行末尾(不能换行);
  • 多行注释以/*开头,以*/结尾,注释内容可以有一行或多行。


C语言输出和输入

在C语言中,有三个函数可以用来在显示器上输出数据:

  • puts():只能输出字符串
  • putchar():只能输出单个字符
  • printf():可以输出各种类型的数据
puts() 函数在输出结束时会自动换行,而 printf() 和 putchar() 不会,需要手动添加换行符\n
printf() 是最灵活、最复杂、最常用的输出函数,完全可以替代 puts() 和 putchar()


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5.     char *str = "c.biancheng.net";
  6.     int n = 100;
  7.     char c = 'Z';
  8.     puts(str);
  9.     putchar(c);
  10.     printf("%d", n);
  11.     putchar(c);
  12.     system("pause");
  13.     return 0;
  14. }

运行结果:
c.biancheng.net
Z100Z请按任意键继续. . .

    程序是人机交互的媒介,有输出必然也有输入。在C语言中,有多个函数可以从键盘获得用户输入:

  • scanf():和 printf() 类似,scanf() 可以输入多种类型的数据。
  • getchar()getche()getch():这三个函数都用于输入单个字符。
  • gets():获取一行数据,并作为字符串处理。
scanf() 是最灵活、最复杂、最常用的输入函数,但它不能完全取代其他函数,大家都要有所了解。


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5.     int a, b, c, d;
  6.     scanf("%d", &a); //输入整数并赋值给变量a
  7.     scanf("%d", &b); //输入整数并赋值给变量b
  8.     printf("a+b=%d\n", a+b); //计算a+b的值
  9.     scanf("%d %d", &c, &d); //输入两个整数并分别赋值给c、d
  10.     printf("c*d=%d\n", c*d); //计算c*d的值
  11.     system("pause");
  12.     return 0;
  13. }

运行结果:
12↙
60↙
a+b=72
10 23↙
c*d=230

↙表示按下回车键。


数组和结构体

数组的定义方式:

dataType  arrayName[length];
dataType 为数据类型,arrayName 为数组名称,length 为数组长度。例如:
float m[12];
char ch[9];
需要注意的是:
1) 数组中每个元素的数据类型必须相同,对于int a[4];,每个元素都必须为 int。
2) 数组是一个整体,它的内存是连续的,下面是int a[4];的内存示意图:

上面的代码是先定义数组再给数组赋值,我们也可以在定义数组的同时赋值:
int a[4] = {20, 345, 700, 22};
{ }中的值即为各元素的初值,各值之间用,间隔。
对数组赋初值需要注意以下几点:
1) 可以只给部分元素赋初值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:
int a[10]={12, 19, 22 , 993, 344};
表示只给 a[0]~a[4] 5个元素赋值,而后面5个元素自动赋0值。
当赋值的元素少于数组总体元素的时候,剩余的元素自动初始化为 0:对于short、int、long,就是整数0;对于char,就是字符 '\0';对于float、double,就是小数0.0。


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int a[6] = {299, 34, 92, 100};
  5.     int b[6], i;
  6.     //从控制台输入数据为每个元素赋值
  7.     for(i=0; i<6; i++){
  8.         scanf("%d", &b[i]);
  9.     }
  10.     //输出数组元素
  11.     for(i=0; i<6; i++){
  12.         printf("%d ", a[i]);
  13.     }
  14.     putchar('\n');
  15.     for(i=0; i<6; i++){
  16.         printf("%d ", b[i]);
  17.     }
  18.     putchar('\n');
  19.    
  20.     return 0;
  21. }

运行结果:

90 100 33 22 568 10
299  34  92  100  0  0
90  100  33  22  568  10
上节讲解的数组可以看作是一行连续的数据,只有一个下标,称为一维数组。在实际问题中有很多数据是二维的或多维的,因此C语言允许构造多维数组。


二维数组的定义

二维数组定义的一般形式是:

dataType arrayName[length1][length2];
其中,dataType 为数据类型,arrayName 为数组名,length1 为第一维下标的长度,length2 为第二维下标的长度。
【示例】一个学习小组有5个人,每个人有三门课的考试成绩。求全组分科的平均成绩和各科总平均成绩。
--
Math 80 61 59 85 76
C 75 65 63 87 77
English 92 71 70 90 85

可设一个二维数组a[5][3]存放五个人三门课的成绩。再设一个一维数组v[3]存放所求得各分科平均成绩,设变量average 为全组各科总平均成绩。编程如下:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     int i, j; //二维数组下标
  4.     int sum=0; //当前科目的总成绩
  5.     int average; //总平均分
  6.     int v[3]; //各科平均分
  7.     int a[5][3]; //用来保存每个同学各科成绩的二维数组
  8.     printf("Input score:\n");
  9.     for(i=0; i<3; i++){
  10.         for(j=0; j<5; j++){
  11.             scanf("%d", &a[j][i]); //输入每个同学的各科成绩
  12.             sum+=a[j][i]; //计算当前科目的总成绩
  13.         }
  14.         v[i]=sum/5; // 当前科目的平均分
  15.         sum=0;
  16.     }
  17.     average =(v[0]+v[1]+v[2])/3;
  18.     printf("Math: %d\nC Languag: %d\nEnglish: %d\n", v[0], v[1], v[2]);
  19.     printf("Total:%d\n", average);
  20.     return 0;
  21. }


运行结果:
Input score:
80 61 59 85 76 75 65 63 87 77 92 71 70 90 85↙
Math: 72
C Languag: 73
English: 81
Total:75

二维数组的初始化

二维数组的初始化可以按行分段赋值,也可按行连续赋值。

例如对数组a[5][3],按行分段赋值可写为:
int a[5][3]={ {80,75,92}, {61,65,71}, {59,63,70}, {85,87,90}, {76,77,85} };
按行连续赋值可写为:
int a[5][3]={80, 75, 92, 61, 65, 71, 59, 63, 70, 85, 87, 90, 76, 77, 85};
这两种赋初值的结果是完全相同的。

数组(Array)是一组具有相同类型的数据的集合。但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组为字符,成绩为小数,因为数据类型不同,显然不能用一个数组来存放。


在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据。结构体的定义形式为:


struct 结构体名{
    结构体所包含的变量或数组
};

结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。请看下面的一个例子:

点击(此处)折叠或打开

  1. struct stu{
  2.     char *name; //姓名
  3.     int num; //学号
  4.     int age; //年龄
  5.     char group; //所在学习小组
  6.     float score; //成绩
  7. };

stu 为结构体名,它包含了 5 个成员,分别是 name、num、age、group、score。结构体成员的定义方式与变量和数组的定义方式相同,只是不能初始化。

注意大括号后面的分号;不能少,这是一条完整的语句。

结构体也是一种数据类型,它由程序员自己定义,可以包含多个其他类型的数据。

既然结构体是一种数据类型,那么就可以用它来定义变量。例如:

struct stu stu1, stu2;
定义了两个变量 stu1 和 stu2,它们都是 stu 类型,都由 5 个成员组成。注意关键字struct不能少。

stu 就像一个“模板”,定义出来的变量都具有相同的性质。也可以将结构体比作“图纸”,将结构体变量比作“零件”,根据同一张图纸生产出来的零件的特性都是一样的。

你也可以在定义结构体的同时定义结构体变量:


点击(此处)折叠或打开

  1. struct stu{
  2.     char *name; //姓名
  3.     int num; //学号
  4.     int age; //年龄
  5.     char group; //所在学习小组
  6.     float score; //成绩
  7. } stu1, stu2;

成员的获取和赋值

结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义。数组使用下标[ ]获取单个元素,结构体使用点号.获取单个成员。获取结构体成员的一般格式为:

结构体变量名.成员名;

通过这种方式可以获取成员的值,也可以给成员赋值:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     struct{
  4.         char *name; //姓名
  5.         int num; //学号
  6.         int age; //年龄
  7.         char group; //所在小组
  8.         float score; //成绩
  9.     } stu1;
  10.     //给结构体成员赋值
  11.     stu1.name = "Tom";
  12.     stu1.num = 12;
  13.     stu1.age = 18;
  14.     stu1.group = 'A';
  15.     stu1.score = 136.5;
  16.     //读取结构体成员的值
  17.     printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", stu1.name, stu1.num, stu1.age, stu1.group, stu1.score);
  18.     return 0;
  19. }

运行结果:
Tom的学号是12,年龄是18,在A组,今年的成绩是136.5!

除了可以对成员进行逐一赋值,也可以在定义时整体赋值,例如:

点击(此处)折叠或打开

  1. struct{
  2.     char *name; //姓名
  3.     int num; //学号
  4.     int age; //年龄
  5.     char group; //所在小组
  6.     float score; //成绩
  7. } stu1, stu2 = { "Tom", 12, 18, 'A', 136.5 };


分支结构和循环结构

if else语句

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int age;
  5.     printf("请输入你的年龄:");
  6.     scanf("%d", &age);
  7.     if(age>=18){
  8.         printf("恭喜,你已经成年,可以使用该软件!\n");
  9.     }else{
  10.         printf("抱歉,你还未成年,不宜使用该软件!\n");
  11.     }
  12.     return 0;
  13. }

if语句的嵌套

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     int a,b;
  4.     printf("Input two numbers:");
  5.     scanf("%d %d",&a,&b);
  6.     if(a!=b){ //!=表示不等于
  7.         if(a>b) printf("a>b\n");
  8.         else printf("a);
  9.     }else{
  10.         printf("a=b\n");
  11.     }
  12.     return 0;
  13. }

for循环语句
for 循环的一般形式为:

for(表达式1; 表达式2; 表达式3){
    语句块
}

它的运行过程为:
1) 先执行“表达式1”。

2) 再执行“表达式2”,如果它的值为真(非0),则执行循环体,否则结束循环。

3) 执行完循环体后再执行“表达式3”。

4) 重复执行步骤 2) 和 3),直到“表达式2”的值为假,就结束循环。

上面的步骤中,2) 和 3) 是一次循环,会重复执行,for 语句的主要作用就是不断执行步骤 2) 和 3)。

“表达式1”仅在第一次循环时执行,以后都不会再执行,可以认为这是一个初始化语句。“表达式2”一般是一个关系表达式,决定了是否还要继续下次循环,称为“循环条件”。“表达式3”很多情况下是一个带有自增或自减操作的表达式,以使循环条件逐渐变得“不成立”。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     int i, sum=0;
  4.     for(i=1; i<=100; i++){
  5.         sum+=i;
  6.     }
  7.     printf("%d\n",sum);
  8.     return 0;
  9. }


C语言指针

计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用4个字节,char 占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。

下图是 4G 内存中每个字节的编号(以十六进制表示):


我们将内存中字节的编号称为地址(Address)指针(Pointer)。地址从 0 开始依次增加,对于 32 位环境,程序能够使用的内存为 4GB,最小的地址为 0,最大的地址为 0XFFFFFFFF。

下面的代码演示了如何输出一个地址:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     int a = 100;
  4.     char str[20] = "c.biancheng.net";
  5.     printf("%#X, %#X\n", &a, str);
  6.     return 0;
  7. }

%#X表示以十六进制形式输出,并附带前缀0X。a 是一个变量,用来存放整数,需要在前面加&来获得它的地址;str 本身就表示字符串的首地址,不需要加&

数据和代码都以二进制的形式存储在内存中,计算机无法从格式上区分某块内存到底存储的是数据还是代码。当程序被加载到内存后,操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据。
CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。
需要注意的是,虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符,但在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址。

定义指针变量

数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。指针变量的值就是某份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外的一个普通变量或指针变量。
定义指针变量与定义普通变量非常类似,不过要在变量名前面加星号
*,格式为:

datatype *name;

或者

datatype *name = value;

*表示这是一个指针变量,datatype表示该指针变量所指向的数据的类型 。

点击(此处)折叠或打开

  1. int a = 100;
  2. int *p_a = &a;
在定义指针变量 p_a 的同时对它进行初始化,并将变量 a 的地址赋予它,此时 p_a 就指向了 a。值得注意的是,p_a 需要的一个地址,a 前面必须要加取地址符&,否则是不对的。

和普通变量一样,指针变量也可以被多次写入,只要你想,随时都能够改变指针变量的值,请看下面的代码:

点击(此处)折叠或打开

  1. //定义普通变量
  2. float a = 99.5, b = 10.6;
  3. char c = '@', d = '#';
  4. //定义指针变量
  5. float *p1 = &a;
  6. char *p2 = &c;
  7. //修改指针变量的值
  8. p1 = &b;
  9. p2 = &d;

*是一个特殊符号,表明一个变量是指针变量,定义 p1、p2 时必须带*。而给 p1、p2 赋值时,因为已经知道了它是一个指针变量,就没必要多此一举再带上*,后边可以像使用普通变量一样来使用指针变量。也就是说,定义指针变量时必须带*,给指针变量赋值时不能带*。


通过指针变量取得数据

指针变量存储了数据的地址,通过指针变量能够获得该地址上的数据,格式为:

*pointer;

这里的*称为指针运算符,用来取得某个地址上的数据,使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价要高。请看下面的例子:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int main(){
  3.     int a = 15;
  4.     int *p = &a;
  5.     printf("%d, %d\n", a, *p); //两种方式都可以输出a的值
  6.     return 0;
  7. }


关于 * 和 & 的谜题

假设有一个 int 类型的变量 a,pa 是指向它的指针,那么*&a&*pa分别是什么意思呢?

*&a可以理解为*(&a)&a表示取变量 a 的地址(等价于 pa),*(&a)表示取这个地址上的数据(等价于 *pa),绕来绕去,又回到了原点,*&a仍然等价于 a。

&*pa可以理解为&(*pa)*pa表示取得 pa 指向的数据(等价于 a),&(*pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa。

对星号*的总结

在我们目前所学到的语法中,星号*主要有三种用途:
  • 表示乘法,例如int a = 3, b = 5, c;  c = a * b;,这是最容易理解的。
  • 表示定义一个指针变量,以和普通变量区分开,例如int a = 100;  int *p = &a;。
  • 表示获取指针指向的数据,是一种间接操作,例如int a, b, *p = &a;  *p = 100;  b = *p;。


const 和指针

当使用带有const的指针时其实有两种意思。一种指的是你不能修改指针本身的内容,另一种指的是你不能修改指针指向的内容。听起来有点混淆一会放个例子上来就明白了。

点击(此处)折叠或打开

  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;

  4. int main()
  5. {
  6.     int a=1;
  7.     int b = 100;
  8.     /*定义指向const的指针(指针指向的内容不能被修改), 初始化与否都可以*/
  9.     const int *p1 = &a;
  10.     //const int*p1 = &a; //*的前后有无空白符都无所谓
  11.     //int const *p1; //也可以先不初始化,另外int和const交换位置无所谓
  12.     printf("%#X %d\n", p1, *p1); // 输出值为1
  13.     a = 2; //OK,仍然可以通过原来的声明修改值,
  14.     printf("%#X %d\n", p1, *p1); // 输出值为2
  15.     p1 = &b; //OK,指针还可以指向别处,因为指针只是个变量,可以随意指向;
  16.     printf("%#X %d\n\n", p1, *p1); // 输出值为100
  17.     //*p1=8; //不正确(指针指向的内容不能被修改)
  18.     
  19.     /*定义const指针(由于指针本身的值不能改变所以必须得初始化)*/
  20.     int * const p3=&a;
  21.     printf("%#X %d\n", p3, *p3); // 输出值为2
  22.     a = 3;
  23.     printf("%#X %d\n", p3, *p3); // 输出值为3
  24.     *p3 = 4; //正确
  25.     printf("%#X %d\n\n", p3, *p3); // 输出值为4
  26.     //p3 = &b; //不正确(指针本身的值不能改变)
  27.    
  28.     /*指针本身和它指向的内容都是不能被改变的所以也得初始化*/
  29.     const int * const p4=&a;
  30.     //int const* const p4=&a; //另外一种形式
  31.     printf("%#X %d\n", p4, *p4); // 输出值为4
  32.     a = 5; //OK,仍然可以通过原来的声明修改值
  33.     printf("%#X %d\n\n", p4, *p4); // 输出值为5
  34.     //p4=&b;//不正确 (指针本身和它指向的内容都是不能被改变)
  35.     //*p4=7; //不正确(指针本身和它指向的内容都是不能被改变)
  36.     return 0;
  37. }

结果:
0X758BCE14 1
0X758BCE14 2
0X758BCE10 100


0X758BCE14 2
0X758BCE14 3
0X758BCE14 4


0X758BCE14 4
0X758BCE14 5








阅读(1899) | 评论(0) | 转发(0) |
0

上一篇:python simulation入门

下一篇:C++入门

给主人留下些什么吧!~~