1、C语言笔记C语言的基本概念编写一个简单的C程序,后缀名保存为c(本次文件名为a.c)gcc:对c程序进行编译和连接;gcc a.c./a.out:运行程序,输出程序的结果;其中a是c程序的文件名说明:其实并不是简单的在a.c文本中输入几行代码就能运行的,其内部实现步骤如下:1:gcc -E a.c 在c程序中有个#include的头文件,其中#开始的命令都叫做预处理命令,这里是把文件通过预处理器进行处理2:gcc -c a.c 对文件进行编译成机器认识的二进制的格式的目标代码,然后就出现一个a.o文件3:gcc a.o 把目标代码和其他的附加代码整合在一起,这样就有一个可以执行的程序a.out
2、4:执行a.out就能够得到程序的结果注意:上面的例子中只使用了gcc a.c 对c程序进行编译和连接;然后./a.out来输出,并没有使用 1,2,3步骤;事实上gcc a.c 这一表达式已经完成编译和连接两个步骤,也就是说执行完gcc a.c之后,就已经生成out文件了,下面来了解gcc的命令参数就知道了;gcc命令的参数讲解-c:只编译,不连接成为可执行的文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件-o output_filename:确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个
3、选项,gcc就给出预设的可执行文件a.out,所以上边例子的gcc a.c执行后就直接生成了out后缀文件,所以就省略了1-2-3步骤(gcc -o b.o a.c /这里是把a.c文件生成b.o文件,如果不为b文件指定o为后缀,那就只生成b文件)-g:产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项,这个参数一样可以生成out的后缀文件-O:对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些;这个参数一样可以生成out的后缀文件-O2
4、:比-O更好的优化编译、连接,当然整个编译、连接过程会更慢;这个参数一样可以生成out的后缀文件-std:选择编译程序所使用的c语言的标准,可以使用-std=c89 或者 -std=c99;这个参数一样可以生成out的后缀文件注释/*/:多行注释,一般用来对描述参数,程序信息/:单行注释,一般用来描述语法的讲解,每行语法对应一行单行注释例如:/*文件名:作者:年份:版本信息:*/#include /头文件_基本类型char:字符类型char c1 = a; /输出achar c2 = 97; /97是ASCII转码 代表achar c3 = 3; /输出3char c4 = / /printf
5、(%d,c4); /输出这个/号的ASCII转码关键字sizeof:在printf中用来测量变量和类型在内存中所占的字节数sizeof(c); /变量sizeof(char); /类型sizeof(表达式); /他只关心括号里的类型占的字节大小,不会对表达式进行运算:int ashort o=9; a=sizeof(o=10); /只输出o类型占内存的大小,不会输出o=10;所以a等于o占内存字节的大小,而不是10;输出的是字节数值无符号整型:就是没有负号的整型数,其永远只有正数_二进制负十进制转换为二进制按位取反-加1负二进制转换为十进制减1-按位取反_判断运算符!= /表示不等于逻辑运算符
6、&:与|:或!:非短路特性:int i=0,j=0;if(+i|+j); /当运算+i得出结果时,就不会再去运算+j,所以这里+j无效,j还是等于0if(-i&+j); /当运算-i得出结果时,就不会再去运算+j,所以这里+j无效,j还是等于0printf(%d %d,i,j); /经过两次运算,i最后还是0,j还是0_位运算:按位取反;如果是整数,运算后就是负数,同样负数运算后得到的是正数;3=-4; 4=-5 ;(n+1)&:按位与;两个二进制数进行与运算时,如果两个数都为真,其结果为真,如果两位数中有一位为假,其结果为假|: 按位或:两个二进制数进行与运算时,只要其中一个数为正,其对应的
7、位就为真:按位异或;一真一假为真,另外如果两个都是真或都是假,其结果都为假:右移左移一位 相当于乘以2右移一位 相当于除以2逗号运算符在C语言中,多个表达式可以用逗号分开,其中用逗号分开的表达式的值分别结算,但整个表达式的值是最后一个表达式的值假设b=2,c=7,d=5,a1=(+b,c-,d+3); /有三个表达式,用逗号分开,所以最终的值应该是最后一个表达式的值,也就是d+3,为8,所以a1=8a2=+b,c-,d+3; /这时的三个表达式为a2=+b、c-、d+3,(这是因为赋值运算符比逗号运算符优先级高)所以最终表达式的值虽然也为8,但a2=3。注意:上面两个算法没有连续关系,所以第一
8、次的+b的值不能作为第二次的+b值继续运算,因此第二次的+b结果是3还有一种情况:x=3,y=5;a=(x+3,y+,x+); /x+3的结果没有指定赋值,会被丢掉,这里的a=3 ;x=4 ;y=5a=(x+,x+3,x+7); /x+的结果保存下来,x+3的结果丢掉,a=11; x=4_缓冲区scanf:#includemain()int data1,data2;printf(请输入两个数字n); scanf(%d,&data1);scanf(%d,&data2);printf(%d %d,data1,data2);说明:如果输入1 3 得到的结果是正确的,但是如果输入的1 r 得到的是1和
9、0,如果输入的是r 1 那么两个输出都是0因为,只有当第一个数据读走时,才会清除这个数据,当第一个是0时,0就不会被清除,导致第二个还是0这里的0是指错误码。也是变量的初始值解决方法:scanf(%*n); /*忽略读到的内容,n任何非n的字符将n之前的所有字符读走到缓冲区,这样你输入的路七八糟的字符都会被读入到缓冲区scanf(%*c); /从缓冲区读取一个字符,这样就把乱码读走了,不会影响第二个数据的正常输入实例:#includemain()int data1=0,data2=0;printf(请输入两个数字n); if(scanf(%d,&data1)=0) /如果=0.就执行上面的解决
10、方法,就能把字符读走了scanf(%*n); /把n之前的所有字符读走,包含n,之后就不能通过n来完成输入,每输入一个数字都要按回车键了scanf(%*c); /读取所有字符忽略掉if(scanf(%d,&data2)=0)scanf(%*n);scanf(%*c);printf(%d %d,data1,data2);人工刷新输出:fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃非标准fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上printf(.);后面加fflush(stdout);可提高打印效率_数组数组初始化int a5=0
11、; /这样就全部都初始化了int a30=10=4, 9=8, 23=67; /这样就对指定的元素初始化,并且没有初始化的都默认为0,这样也不存在顺序问题sizeof:测试数组的大小sizeof(数组字节)=sizeof(数组元素字节)*元素的个数 如:int a10; sizeof(a)=sizeof(a0)*10printf(%d,sizeof (a0) /求数组元素的字节printf(%d,sizeof (a) /求数组的字节如:int a10 /int占4个字节,a就是40字节,在除以每个元素的字节a0=4,就是数组的长度二维数组int a34=0; /对所有的元素进行初始化为0_函数
12、#include#includebool prime(int data)int i=2;for(;idata;i+)if(data%i=0)return false; /假return true; /真main()int d=0;printf(输入一个数);scanf(%d,&d);printf(%sn,prime(d)?素数:合数); /为真选择素数,为假选择合数,输出是字符串exit:函数名: exit()所在头文件:#include 功 能: 关闭所有文件,终止正在执行的程序。exit(1)表示异常退出.这个1是返回给操作系统的不过在DOS好像不需要这个返回值exit(x)(x不为0)都
13、表示异常退出exit(0)表示正常退出用 法: void exit(int status);exit()和return的区别:按照ANSI C,在最初调用的main()中使用return和exit()的效果相同。但要注意这里所说的是“最初调用”。如果main()在一个递归程序中,exit()仍然会终止程序;但return将控制权移交给递归的前一级,直到最初的那一级,此时return才会终止程序。return和exit()的另一个区别在于,即使在除main()之外的函数中调用exit(),它也将终止程序。#include #include #include int main(void)char
14、status;printf(Enter either 1 or 2n);status = getch(); /获取一个字符exit(status - 0); /status减去字符0的ASCII码printf(%dn,status); /字符以%d形式输出return 0;_变量的类别局部变量:在函数体内定义的变量生命周期:从定义这个局部变量的地方开始到函数的结束作用范围:在定义这个局部变量的函数内static:静态局部变量,其数值就是上一次函数调用结束之后的数值,还可以修饰函数:static int a(int a);生命周期:整个程序作用范围:和普通局部变量一样全局变量:定义在整个程序中的
15、变量称为 全局变量生命周期:整个程序的生命周期之内作用范围:整个程序的范围内都可以访问全局变量在定义之后自动初始化为0块变量:定义在 程序块 里面的变量叫做块变量程序块:使用 括起来的一组语句,比如 if 语句里的或者是循环语句等使用到 的地方生命周期:定义变量的地方开始,程序块结束的地方消失作用范围:程序块内rand();:随机生成一个数#include#include#includemain()int data = 0;srand(time(0); /随机数发生器的初始化函数,为了防止随机数每次重复常常使用系统时间来初始化;time(0)取得当前时间(秒的总和)data = rand()%
16、100; /初始化随机数,取100内的数赋值给datawhile(t=time(0); /延迟 让程序等待这一秒过去 printf(%dn,data);time(0)%100 /当前秒总和int t;t=(time(0)%100)+5); /当前时间+5赋值给tprintf(%dn,t); /打印t的值while(t(time(0)%100); /延迟5秒。当表达式为真,执行循环,为假退出循环,刚好5秒register:寄存器,register int a;告诉编译器这个变量会被频繁的使用,请保存到寄存器中不能对寄存器变量取地址&有些系统不会把register修饰的变量放到寄存器中,由编译器决
17、定const:只读变量修饰符,变量的数值是不能被改变的volatile:一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会;确保本条指令不会因编译器的优化而省略,且要求每次直接读值XBYTE2=0x55;XBYTE2=0x56;XBYTE2=0x57;XBYTE2=0x58;对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器就不能像对待纯粹的程序那样对上述四条语句进行优化,只认为XBYTE2=0x58(即忽略前三条语句,
18、只产生一条机器代码)。如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(四条).定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:1). 并行设备的硬件寄存器(如:状态寄存器)2). 一个中断服务子程序中会访问到的非自动变量3). 多线程应用中被几个任务共享的变量_指针 int *q=NULL; /指针初始化注意: 不要返回一个局部变量的指针char a10; a=add; /这
19、种赋值是错的char a10; a0=b; /这种是对的,意思为第一个赋值一个字符b_程序段:就是一段程序(可以是一个子过程SUB,一个函数FUNCTION(用面向对象的观点或称为方法) 程序都是从上到下施行的,那应该什么时候用到程序段数据段:在采用段式内存管理的架构中,数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。bss段:通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域_堆和栈堆栈二者特性不同,各有适用场合。首先,最重要的一点,对象生存期不同。栈上的空间,是自动回收的,虽然省事,但如果不想让它自动回收,就要
20、使用堆来创建对象;在一个函数内部创建一个对象,然后把它的地址传给函数外层用,就不能在栈上创建这个对象,因为当函数一结束,此对象就被销毁了,外面访问它会出错。而堆的话由于是完全手工创建手工回收,在碰到delete之前这个对象是不会被销毁的,就可以随意传递。堆上申请空间可以很大,但是栈的空间却很有限,根据操作系统不同而不同,一般只有14MB的大小,如果在栈上申请过大的空间就会出错。最后,栈上申请空间的速度比堆上快得多,所以如果是函数内部临时使用的小对象,一般用栈来分配。栈:它是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取堆:堆的存取是随意,如同我们在图书馆的书架上取书char
21、 *p1; /全局未初始化区 main() int b; /栈 char s = abc; /栈 char *p2; /栈 char *p3 = 123456; / 1234560在常量区,p3在栈上。 p1 = (char *)malloc(10); 堆 p2 = (char *)malloc(20); 堆 栈是系统自动分配空间的,栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。堆则是程序员根据需要自己申请的空间,例如malloc(10);开辟十个字节的空间。而堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。堆内存申请:new
22、:申请堆内存malloc:申请堆内存:a=(int*)malloc(100*sizeof(int);delete :释放堆内存空间,指向堆内存首元素的指针;如果申请的是一个堆内存变量,则delete后的可以省略;如果申请的是一个堆内存数组,则该不能省略#include iostream.hint main()int size;float sum=0;int *heapArray;cout size;heapArray=new intsize; /申请堆内存cout 请输入各元素: endl;for (int i=0;iheapArrayi;sum=sum+heapArrayi;cout 这些数
23、的平均值为 sum/size endl;delete heapArray; /释放堆内存return 0;注意:这里使用到了两个输入输出关键字:cout,cin输出输入#include iostream.h /使用头文件cout result=resultsize;_读写一个字符串puts:输出一个字符串,可以指定一个文件指针,把字符串输出到文件中,也可以输出到显示设备上fputs#includemain()char a=1a3456;/*字符数组也可以定义数字,但输出的是ascll,并非数字*/printf(%dn,+a0);/*输出的是字符1的ASCII码,1的ASCII 码为49,+a0后等于50*/ printf(
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1