C语言中重要基础知识的概述

来源:互联网 发布:sql中的服务器名称 编辑:程序博客网 时间:2024/05/08 13:24


本章主要对于C语言中的基础知识进行一个大致的描述,适合有C语言基础但长久没接触C语言开发的人员进行快速回忆。在总体回忆基础知识之前,先来创建一个C程序。笔者的编译器是visual stduio2013。


一、建立C项目:





建立一个项目,此项目因为是C语言的开发环境,而C++兼容C语言,所以选择Visual c++项目,选择win32控制台项目,名称和位置可以自己设置。然后点击确定。




点击下一步




注意默认的是C++项目,会含有C++的编译头文件,所以我们必须勾选空项目选项,从而建立一个不含任何文件c项目,这样在后期生成文件的时候才不会出错。点击完成。




点击解决方案资源管理器,右击源文件来添加新建项,这样就可以建立c文件了。




选择c++文件,注意此时名称的文件名称默认是以cpp结尾的,我们需要改成c结尾的。然后添加。


然后添加文件内容,笔者的代码如下:


// test.cpp : 定义控制台应用程序的入口点。//#include <stdio.h>int main(void){double getResult(int n);int n = 0;/*多行注释*/printf("请输入一个整数:");scanf_s("%d", &n);/*scanf函数在新版本被认为是不安全的,所以使用_s后缀版本的安全版本*/printf("结果是:%0.lf\n", getResult(n));//单行注释return 0;}double getResult(int n){double result = 1;for (int i = 1; i <= n; i++){result *= i;}return result;}




按Ctrl+f5运行项目。会弹出一程序控制台,然后就可以运行了。这样就建立了我们的c项目。


二、解读代码,重塑整体回忆


接下来会使用一个例子,里面包含了大量的注释解说,介绍c语言的规则。

// test.cpp : 定义控制台应用程序的入口点。//#include <stdio.h>//此头文件包含基本的操作#include<math.h>//此头文件包含大量的数学函数/*如果方法是在main方法之前定义的,则使用的时候就不需要声明了。此方法用于尝试修改传递的值,但是这是值传递,并不是直接传递实参的对象,而是复制了实参的值进行传递的,所以不能修改修改实参的值,如果要修改实参的值,必须使用指针。*/void canChangeValue(int n){n++;}/*全局变量,全局变量在函数体外生命,它的生命周期会持续知道main函数执行完毕。*/double k = 0;/*函数声明也可以放在main函数外面*/double testSqrt(int temp);int main(void){//声明函数double getResult(int n);void changeGlobal();int changeStatic();int isNGreaterM(int n, int m);/*C语言的数据类型有整型int(32位),short短整型(16位),long(长整型)(32位),字符型char(8位),实型(double(64位),float(32位)),空类型,指针类型以及自定义数据结构类型整型的表示形式有三种,分别是十进制,八进制(首位是0)以及十六进制(首位是0x),比如十进制10=八进制012=十六进制0x0a输入输出格式,%d->以十进制输入输出一个整数,%o->以八进制输入输出一个整数,%x以十六进制输入输出一个整数C语言中字符占8位,字符常量不仅可以用字符的形式表示还可以用数值的形式表示,因为每个字符都对应者一个ASCII码。比如 ch='a'和ch=65是等价的。输入输出格式,%c->输出一个字符型数据实型数据的输入输出格式:%f->以小数形式输入输出一个浮点数,%e->以指数形式输入输出一个浮点数。实型即浮点型,就是我们常说的含有小数的数值。*///声明局部变量int n = 0;/*多行注释*/printf("请输入一个整数:");scanf_s("%d", &n);/*scanf函数在新版本被认为是不安全的,所以使用_s后缀版本的安全版本*/printf("结果是:%0.lf\n", getResult(n));//单行注释//测试实参的值能否通过形参来改变printf("调用canChangeValue方法:可以发现传递的值并没有改变\n");//在调用此函数的时候main函数并没有生命,因为此函数是定义在main函数之前的。canChangeValue(n);printf("调用canChangeValue之后的n值:%d\n", n);//测试全局变量k的值是否改变changeGlobal();printf("调用changeGlobal方法之后,可以发现全局变量的值发生了改变\n调用方法后k的值是:%0.lf\n", k);//测试静态变量printf("第一次调用changeStatic方法,静态变量j的值:%d\n", changeStatic());printf("第二次调用changeStatic方法,静态变量j的值是在第一次调用函数之后的j的值上进行操作的,j的值是:%d\n", changeStatic());//测试c语言中的比较操作printf("如果n>m(1,2)则返回1,否则返回0:%d\n", isNGreaterM(1, 2));printf("如果n>m(3,2)则返回1,否则返回0:%d\n", isNGreaterM(3, 2));//测试c语言的数学函数printf("对4开方:%0.lf\n", testSqrt(4));//测试字符类型/*字符类型的数据的读写除了可以使用scanf,printf外还可以使用putChar,getChar方法,这两个方法只能操作单个字符。注意,空格键也是一个字符,'\'是转义字符。回车键也会产生一个字符。*/printf("请输入一个字符:");//读取键盘输入//用于消耗调用scanf_s("%d", &n)函数按回车键导致的字符getchar();char charItem=getchar();//输出putchar(charItem);putchar('\n');/*以十进制八进制十六进制输出10*/printf("十进制:%d,八进制:%o,十六进制:%x\n", 10, 10, 10);/*以指数形式和小数形式输入150.00*/printf("指数形式:%e,小数形式:%f\n", 150.00, 150.00);/*位运算符,~,|,^,&,<<,>>,除了~是单目运算符外其余全都是双目运算符~表示取反,比如2的二进制表示形式是00000010,~2=11111101.|表示逻辑或,比如00010010|10010001=10010011.&表示逻辑与,比如00010010&10010001=00010000.<<表示左移两位,右边移除的位数舍弃,左边补0,比如:0001001<<2=0100100.>>表示右移两位,左边移除的位数舍弃,右边的首位符号位不变,其余补0比如10001001>>2=10100010*/return 0;}/*阶乘,此方法因为定义在main函数之后,所以使用之前必须声明*/double getResult(int n){double result = 1;for (int i = 1; i <= n; i++){result *= i;}return result;}/*修改全局变量k的值,可以发现,尽管changeGlobal方法并没有声明k但是也可以使用k,因为全局变量的生命周期是在整个程序运行期间都存在的。*/void changeGlobal(){k += 6;}/*修改静态变量的值,静态变量的值是存储在静态存储区的,他不会随着函数的执行完毕而被回收,当再次激活此方法的时候,仍然是使用的上一次保存的值。*/int changeStatic(){//静态变量如果没有显式初始化,那么就会指定一个默认值,这里int类型指定的是0;//注意局部变量如果没有显示初始化,那么系统会用一个随机的值初始化,这会造成意想不到的结果。static int j;j += 10;return j;}/*用于测试n是否大于m,在c语言中是没有面向对象程序设计语言中的布尔值类型的数据的。而是用1代表true,0代表false;*/int isNGreaterM(int n, int m){return n > m;}/*用于给传递的数开方,这是数学函数,有math.h头文件提供常用的数学函数有:sqrt(x):对x进行开方。fabs(x):对x进行取绝对值。pow(x,n):求x的n次方。exp(x):指数函数,即e的x此方。log(x):对数函数。*/double testSqrt(int temp){return sqrt(temp);}

基本上常用的规则都包含在上述的例子中了。


三、C语言中一维数组二维数组以及字符数组的使用与初始化



值得注意的是,在C语言中定义的数组,比如定义了int a[2],a其实是一个地址常量,它指代了a[0]的地址。因为C语言中不能够一次性引用这个数组,所以通常情况下需要借助指针来操作数组。接下来的例子会讲解到这一点,并且还会包含二维数组以及字符数组的使用。


/*数组相关的信息*/#include<stdio.h>void printfGroup(int group[]);void printfStaticGroup();void printfTwoDimessionGroup(int *p, int col, int row);void printfString(char group[], int count);int main(void){/*数组初始化形式如下:不同于其它高级编程语言,C语言中数组的长度是必须指定的。*/int aGroup[5] = { 1, 2, 3, 4, 5 };//输出数组内容/*C语言中,是不能一次引用这个数组的,而aGroup代表的是aGroup[0]的地址,因此传递数组实参的时候,只需要传递数组的首地址即可*/printf("初次输出aGroup的内容\n");printfGroup(aGroup, 5);/*再次输出aGroup的值,证明传递方式是引用传递值传递:是将实参的内容在内存中复制一份再传递,因此对形参的值进行修改不会该表实参的值。引用传递:是将实参的地址传递过去,因此对形参进行修改也会影响实参的内容。*/printf("再次输出aGroup的内容,可以发现数组内容发生了改变,说明传递方式是引用传递\n");printfGroup(aGroup, 5);/*未明确指定的数将被初始化为0*/int bGroup[10] = { 1, 2, 3, 4, 5 };printf("输出bGroup的内容,可以发现后面五个没有显式赋值的元素都是0\n");printfGroup(bGroup, 10);printf("输出静态数组的值\n");printfStaticGroup();printf("再次输出静态数组的值,可以发现静态数组的元素并没有随着printfStaticGroup函数的执行完毕而消失\n");printfStaticGroup();/*二维数组*///这里定义了一个2行3列的数组,赋值的顺序是,从第一行第一列然后是第一行第二列,依次类推int cGroup[2][3] = { 1, 2, 3, 4, 5, 6 };//如果一个二维数组中并没有给全部元素初始化,那么没有初始化的元素会自动初始化为0,赋值顺序和上述一样。在这里即第二行开始全部是0int dGroup[4][4] = { 1, 1, 1, 1 };//这是二维数组的另一种赋值方式int eGroup[3][3] = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } };printf("输出cGroup的值:\n");printfTwoDimessionGroup(cGroup, 3, 2);printf("输出dGroup的值:\n");printfTwoDimessionGroup(dGroup, 4, 4);printf("输出eGroup的值:\n");printfTwoDimessionGroup(eGroup, 3, 3);/*字符数组*///'\0'是字符串结束符的意思,在C语言中,每个字符串都是以'\0'结尾的,因此下面的两个数组是相等的。char fGroup[6] = { 'h', 'a', 'p', 'p', 'y', '\0' };char gGroup[6] = "happy";/*输出上面的字符串*/printfString(fGroup, 6);printf(gGroup,6);printf("\n");return 0;}/*输出数组元素*/void printfGroup(int group[], int count){for (int i = 0; i < count; i++){printf("%d\n", group[i]);//尝试修改数组元素的值,可以发现,数组元素的值是可以修改成功的,说明数组传递方式传递不是值传递而是引用传递。group[i]++;}}/*输出静态数组*/void printfStaticGroup(){//同样的,如果没有显示赋值,那么都会赋值0/*静态元素不会随着函数的执行完毕而消失,而是会一直保存,等到再次调用此函数的时候,又会重新激活。*/static int aGroup[10] = { 1, 2, 3, 4, 5 };for (int i = 0; i < 10; i++){printf("%d\n", aGroup[i]);aGroup[i]++;}}/*输出二维数组,这里用到了指针,指针后续会将,这里先负责演示*/void printfTwoDimessionGroup(int *p, int col, int row){for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){//其实二维数组存储的数据也是存在一块连续的存储空间中的,假如*p指向啊a[0][0]的地址,那么a[0][1]的指针就应该是*(p+1)。即指针值往后移printf("%d ", *(p + i*row + j));}printf("\n");}}/*输出字符串*/void printfString(char group[],int count){for (int i = 0; i < count; i++){printf("%c",group[i]);}printf("\n");}

结果如下:








4、c语言中的指针及其使用和动态申请空间的方法


详情请看注释

/*C语言中的指针*/#include<stdio.h>#include<string.h>#include<stdlib.h>void changeParamByConst(int b);void changeParamByPoint(int *temp);int main(void){//指针的基础知识/*指针变量是一个存放变量地址的值,它的值是指向另一个变量的地址的。‘*’号表示一个指针声明符,下面的即是一个常规的指针声明方式*/int *p, a;printf("输入一个整数:");/*读入一个数字,可以解析为读入一个整数,并将其存放在a变量地址所在的单元里面&是地址操作符*/scanf_s("%d", &a);/*因为p是一个存放地址的变量,因此它的初始化必须是用地址,&a既是取出a的地址的意思。*/p = &a;//接下来输出a的值以及p指向的变量的值。printf("a的值:%d\n", a);printf("p指向的变量的值:%d\n", *p);//这里输出的是p的值即a的存放数据的地址printf("p的值:%d\n", p);//通过指针修改实参变量的值/*一般情况下,函数都是通过值传递的方式来传递值得,此种方法不能改变实参的值。引用传递即传递的是地址,而不是实参本身,所以可以通过修改指针指向的变量的值来达到修改实参的值的目的。*///通过值传递的方式是不能改变实参的值的。changeParamByConst(a);printf("调用了changchangeParamByConst之后,a的值仍然不变:%d\n", a);//通过引用传递的方式调用函数,这种方式是会影响实参的值的。changeParamByPoint(p);printf("调用了changeParamByPoint之后,a的值也被改变了:%d\n", a);/*指针和数组的关系*///此处定义一个数组。上面讲过数组是不可以一次性引用的。group指代的是首地址。//那么与指针变量有什么区别呢。区别在于group是地址常量,即它的值是不可以修改的。//而指针是一个地址变量,它的值是可以修改的。int group[] = { 1, 2, 3, 4, 5, 6, 7 };//因为group指代数组的首地址,因此下面的方式可以用于初始化一个指针。int *pGroup = group;for (int i = 0; i < 6; i++){//其实可以发现指针的使用方式和数组是差不多的printf("%d %d %d %d\n", *(pGroup + i), pGroup[i], group[i], *(group + i));}/*字符数组,字符数组就是我们常说的字符串。*/char s[] = "happy";char *ps = "day";//可以发现字符数组和一般的数组是没有区别的printf("%s %s\n", s, ps);/*字符串操作函数*/char sOne[20] = "happy ";char sTwo[4] = "day";//表示将sTwo的字符连接到sOne中,注意sOne必须要有足够的空间//strcpy表示复制,strlen表示长度,strcmp用于比较两个字符串的大小。strcat(sOne, sTwo);printf("%s\n", sOne);//另外calloc,malloc函数适用于动态申请内存空间的,用完之后记得free掉int *pMalloc;//malloc返回的值是void *,这是个通用的指针类型,因此需要进行转换。if ((pMalloc = (int *)malloc(a*sizeof(int))) == NULL){printf("内存不足");exit(0);}for (int i = 0; i < a; i++){scanf_s("%d", pMalloc + i);}for (int i = 0; i < a; i++){printf("%d ", *(pMalloc + i));}free(pMalloc);return 0;}/*通过值传递的方式修改实参的值,会发现失败的。*/void changeParamByConst(int b){b++;printf("执行b++,输出b的值:%d\n", b);}/*通过引用传递的方式修改实参的值,是可以成功的。*/void changeParamByPoint(int *temp){(*temp)++;;printf("通过(*temp)++;之后的值,%d\n", *temp);}


运行结果:



五、c语言中结构类型与指针的使用


/*C语言结构类型,此类型是可以含有任意C语言的数据类型的数据作为成员的,它可以把含有内在联系的不同的数据联系在一起作为一个整体来使用 */#include<stdio.h>#include"Extern.c"//这种方式用于包含外部文件/*常用的结构类型的声明方式,成员变量可以是任意类型,包含结构类型*//*静态全局变量和普通全局变量的区别在于,静态全局变量只能在当前的文件的函数访问,不能被外部文件的函数访问*/static int staticGlobalInt = 0;int globalInt = 1;struct Person{char name[20];int age;double height;};int main(void){//定义一个名为strcut person的结构类型变量//初始化方式struct Person person = { "huangyi", 20, 213 };//.是成员操作符,可用于操作结构类型的成员//输出person的内容printf("name:%s,age:%d,height:%0.lf\n", person.name, person.age, person.height);//从控制台读取数据给person赋值printf("请输入person的名字,年龄,身高:\n");gets(person.name);scanf_s("%d", &person.age);scanf_s("%0.lf", &person.height);printf("name:%s,age:%d,height:%0.lf\n", person.name, person.age, person.height);/*结构类型数组*/struct Person personGroup[3] = { {"james",31,203}, {"Harden",26,193}, {"Yaoming",37,226} };//和普通数组一样,personGroup代表的也是该数组的首地址for (int i = 0; i < 3; i++){printf("第%d个person,name:%s,age:%d,height:%0.lf\n", i, personGroup[i].name, personGroup[i].age, personGroup[i].height);}/*指针和结构类型*///将指针指向person的地址struct Person *pPerson = &person;printf("name:%s,age:%d,height:%0.lf\n", pPerson->name, pPerson->age,pPerson->height);//将指针修改,指向personGroup的首地址//注意数组和变量之间的去边。pPerson = personGroup;for (int i = 0; i < 3; i++){//下面的两种方式都可以输出内容//->叫做指向运算符,可以指向成员。printf("第%d个person,name:%s,age:%d,height:%0.lf\n", i, (pPerson + i)->name, (pPerson + i)->age, (pPerson + i)->height);printf("第%d个person,name:%s,age:%d,height:%0.lf\n", i, (*(pPerson + i)).name, (*(pPerson + i)).age,(*(pPerson + i)).height);}return 0;}








1 0
原创粉丝点击