C程序设计语言基础
机器语言与高级语言
计算机硬件只能够识别电平信号,正电平或负电平,计算机的的各种按钮触发各种电平与计算机交互。随着随着操作系统的发展,人们用1,0分别表示正电平和负电平,并由0,1所组成的一系列指令指挥计算机工作。
一种由二进制所组成的指令集合称为机器语言。机器语言依赖于硬件,因此也称为低级语言,机器语言全由二进制指令组成难学,难计,难写。
20世纪50年代左右出现了高级语言,高级语言依赖于操作系统,使用字符作为计算机指令,而字符正是自然语言的一部分,更贴合人类的使用习惯。高级语言依赖于操作系统,由操作系统将其转化为字节,在转化为二进制,最后转为硬件指令。
C语言是最流行的系统语言,诞生于贝尔实验室,随着C语言的发展,其移植到各种计算机上,已成为世界上应用最广泛的语言。
后来的许多语言都受到c的影响,大多都是用c来开发,如Java,Python等。高级语言学习更方便也更快捷。
C语言示例
#include<stdio.h>int main(){//声明调用函数int max(int a,int b);int a,b,c;scanf("%d,%d",&a,&b);c = max(a,b);printf("max=%d",c);
}int max(int a,int b){int z;if(a>b) z =a;else z = b; return z;
}/*
1. c语言程序主要有函数组成,函数是c程序的基本单位
2. 变量是程序中传递的方式,有值传递和引用传递
3. 函数的定义语法为:函数返回值类型 函数名 (参数类型 参数 ...) {//变量和方法组成 }例如: int max (int a,int b) {//return 0;}
4. 变量的定义语法为:变量类型 变量名 [= 数据 ] []中为可省略内容
5. #include<stdio.h> 是c语言的标准输入输出库,可以直接用到内部的函数
6. int max(int a,int b) 为函数名部分,{}中的内容为函数的执行体,当函数定义在函数调用之后时需要在调用前声明函数名部分。
7. c语言函数总是从main(主函数开始执行)
8. c语言书写格式自由,语句用;隔开
9. c语言库函数丰富,使用库函数需要# 引入,如 #include<stdio.h>
10.c语言使用 //作为注释,注释不会参与到编译,多行注释
11.c语言是强类型的编译语言,运行时需编译成二进制的可执行文件
*/
多行注释是/*...*/
。
内存存储的方式
c语言的代码会编译成二进制文件,操作系统据可以使用这里二进制指令文件来控制计算机。
在数据存储时,对于计算机来说二进制是可执行的指令集合,计算机的存储器是用半导体集成电路构成的,包含众多脉冲电路,二极管元件,每个二极管元件相当于开关。所以每次都会用两种状态,对电平来说就是正电平和负电平,用1,0表示。如下图
于是由这些二进制组成的计算机指令控制者计算机的硬件。
在计算机中每一个二极管元件成为二进制位,是存储的最小单元,成为比特(bit)
,或者位
。在二进制中,规定每8位组成一组,称为字节(byte)
,即一个字节占8位有8个0,1,共有2^8中状态。
地址
是计算机的存储单元,计算机存储器包含很多存储单元,操作系统将这些单元编号,统称为地址。
在程序设计中,不同类型的数据占据的存储空间不一样,因此语言对占用不同的数据类型进行了分类,成为数据类型
。
如c语言中一般存在如下数据类型:
语法定义法则
变量与常量
c语言中的变量是一个存储单元的地址,变量名代表该地址存储的数值,可以通过&
获取变量的地址。
变量定义以数字,字母或下环线完成,数字不能做首位;变量必须先定义分配存储空间后再使用;
变量定义时可以不初始化可以初始化赋值,如下:
//定义实数
int a1 = 100;
int a2;
a2 = 200;//定义浮点数(小数)
float a3 = 12.21
double a31 = 23.33333333333//定义指数,指数必须为整数,用e,E表示10的阶乘 (%e)
int a4 = 2.3e10 //定义字符
char a5 = "c"//c语言没专门的字符串定义,使用字符数组定义
char a6[10]
变量的格式化打印时
%d,%s,%c,%f,%d,%e
和打印的变量类型要对应。
%.2
表示保留小数点几位。
字符常用用反引号包裹;c中提供了很多转义字符,用来格式化符号,如:
\t 表格分区
\b 退格
\r 回车
\f 换页
\0 字符串的结束标志
\\ 表示一个\
字符再c中是ASCII码中的数据,打印时通过格式化打印对应的数字或者字符,%c,%d
。每一个小写字母比大写字母大32。
c语言再处理自字符时是用''
包裹,而字符串是用""
包裹,后者系统会在字符串后默认加\0
作为结束符,因此字符串占用字符比实际多一个字符。
c语言中使用# define [常量名] [常量值]
的方式定义常量。
#include<stdio.h>
#include<math.h>
//定义常量
#define PI 3.1415926 int main(){float a = 12.43;printf("%f\n",a); int b = 'c';printf("%c\n",b );char c = 'a';printf("%c\n",c);//数学计算库double r =3,d,e,f;//圆周率 d = 2*3.1415926*r; //面积e = 2*3.1415926*r*r;// 体积f = (4.0/3.0)*(3.1415926*r*r*r);printf("c=%f,s=%f,v=%f\n",d,e,f); //使用数学计算库pow方法 double v;v=(4.0/3.0)*(3.1415926*pow(r,3));printf("数学计算库:%f\n",v);//定义常量 计算double v1;v1 = 4.0/3.0*PI*pow(r,3);printf("常量计算:%f\n",v1); return 0;
}
指针变量,是c语言提供直接操作内存地址的变量,通过类型 * 变量名
来定义,表示该指针变量。通过&
取出其地址。(指针章节详述)
输入输出函数是printf
,scanf
分别使用%d,%s,%c,%f,%d,%e
作为输入和输出的格式控制符,另外scanf函数格式控制后的变量是变量地址,而不是变量名,且在输入是,格式控制符没有任何符号就默认用空格隔开,声明了相应符号输入时就要在对应位置输入相同的符号。
运算符注意事项
- 除法运算
/
时两个整数的相除结果仍然是整数,c自动去除小数部分。 - 运算符的优先级与数学规定的相同。
- 当运算时出现了flaot和double类型,所有的数据都会转为double,提高精度。
- c提供自增和自减运算,
++i
表示使用变量i前先加一,i++
表示使用后变量加一。
#include<stdio.h>int main(){int i = 3;printf("%d\n",++i);int j = 3;printf("%d\n",j++);return 0;
}
自增和自减完成后都会重新赋给变量,另外自增与自减只用用变量来操作不能用数字,而且变量不能参杂任何表达式
(a+b) ++
,这也是错误的。
- 在混合计算的过程中,字节少的数据会自动转化为字节多的数据。
- 在类型转换过程中字节少的数据会自动转化为字节多的数据,多字节转化为少字节的需要强制转换,
(类型名) (表达式)
强制转化会丢失精度。 *
用于定义指针变量,&
取变量地址。
库与函数的使用
c语言提供了丰富的库函数,只要导入了相关库就可以使用库方法。在其他语言中也叫内置方法。在使用库函数时,要在库函数中使用预编译指令#include
加载库。目的时将相关的 ”头文件“的内容引入到头文件中。#include
也被称为头文件。
库的存在使代码不至于都写在一个文件中,将一部分代码写在库文件中,需要时引入头文件即可。引入头文件主要包含# include 文件目录和文件名
,如
#inlcude <stdio.h>
这是c语言的提供的标准输入输出库,导入该头文件后可以使用:putchar,getchar,printf,scanf,puts,gets
等库方法。
#include
是预编译指令,为导入头文件的关键字,<stdio.h>
是文件名,用<>
包裹起来,表示编译器会在编译系统所在的子目录查找stdio.h
文件。如
#include "C:\tmp\c_header_file\test.h"
除了c语言自带的标准库外,可以引入自定义的库文件用""
代替<>
。区别在于""
会在用户当前目录下寻找库文件,而<>
会在c编译环境目录下寻找库文件。
因此,C语言提供了两种文件命令方式.h
和.c
。在C语言中,数据结构及函数的声明与实现进行分离有且仅有一种搭配方式:.h .c
。
.h
用于数据结构及函数的声明
.c
用于数据结构的初始化及函数的具体实现
在C++中,数据结构及函数的声明与实现进行分离的方式有两种:①.h、.cpp;②.hpp。具体可以参考游戏开发之.h、.c、.hpp及.cpp的区别
因此当程序仅仅是数据结构或者工具函数时,将函数保存为.h
文件,通过头文件导入后就可以使用其数据结构和工具函数了。
自定义addSum头文件
在主类引入头文件,并调用函数
调用成功
malloc函数
malloc(长度)
是动态开辟内存空间函数,表示向系统申请分配一个占参数长度字节的空间。
程序与算法
在程序中指定数据的类型和数据的组织形式就是数据结构
(data structure)。算法
是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。
算法可以用多种方式表示,自然语言,流程图,N-S图,伪代码等。程序中的基本结构包括,顺序结构,选择结构和循环结构。
选择结构
#include<stdio.h>int main(){int tmp;scanf("%d",&tmp);if(tmp>60){printf("%s","及格了!");}else{printf("未及格!"); }return 0;
}//else总是与其上面一个if匹配//如果有多个选择还可以用 else if (表达式) 继续判断#include<stdio.h>int main(){int tmp;scanf("%d",&tmp);if( tmp = 0 ||tmp<60){printf("%s","未及格!");}else if ( 60 <= tmp && tmp <80){printf("%s","良好!");} else if ( 80<= tmp){printf("%s","优秀!");}else printf("%s","未查到分数!");return 0;
}
switch语句
int main(){int tmp;scanf("%d",&tmp);switch(tmp){case 60 : printf("未及格!"); case 80 :printf("%s","良好!");case 100 : printf("%s","优秀!");default : printf("%s","未查到分数!");}
}
switch
括号的表达式只能时数值类型或者字符类型;当表达式的值与某个case
的值相等时,就会执行其后的语句,如果没有匹配的就执行default;每个表达式的值必须互不相同。执行完一个case后,流程会转到下一个case继续继续执行,因此需要控制流程找到分支后退出,通过break
语句·。
switch(tmp){case 60 : printf("未及格!"); break;case 80 :printf("%s","良好!"); break;case 100 : printf("%s","优秀!"); break;default : printf("%s","未查到分数!");
}
循环结构
循环结构的条件:1、需要重复执行的操作(循环体);2、循环结束条件。
while 表达式 语句
#include<stdio.h>
int main(){int i,range;i = 0; range =100;while (i<range){i++;range--;}printf("i=%d,range=%d",i,range);
}
do
循环体语句while(表达式)
循环体语句超过一个要用{}
包裹,循环体中要有结束循环的条件。
第一个循环为先判断表达式后执行循环体;第二个为先执行循环体再判断表达式是否成立。相同点时表达式为真时均继续执行循环。
for循环
for(表达式1,表达式2,表达式3) 语句
for(循环变量赋初值;循环条件;循环增量) 语句
#include<stdio.h>
int main(){int sum = 0;int i =0;for(i = 0;i<=100;i++){int tmp = i;sum+=i; }printf("%d",sum);return 0;
}
break
用于结束循环,continue
结束本次循环。
for循环的表达式都可以省略for(;;)
。
数组
数组是具有同一属性的数据集合。在c语言中,定义数组时,需要指定变量的类型,数组名称和数组中包含多少个元素。
定义数组的格式:
类型 数组名[常量表达式]
定义数组时,需要指定数组元素的个数,括号中表达式表示元素的个数,即数组的长度;数组的大小不依赖于运行程序的变量;数组的元素只能变遍历;通过数组的下标取出数组的元素。
数组也可以初始化定义,再初始化定义时如何长度和初始化长度一致
//冒泡算法#include<stdio.h>int main(){int a[10] = {10,9,8,7,6,5,4,3,2,1};int i,j,t;for(i=0;i<=9;i++){for(j = 0; j<9-i;j++){if(a[j]>a[j+1]){t = a[j];a[j] = a[j+1];a[j+1] =t;}}}int z;for(z=0;z<10;z++){printf("%d",a[z]);}
}
二维数组
二维数组中元素的排序顺序是按行存放的,即在内存中存放第一行的元素在存放第二行元素。
定义二维数组
数组名 [下标] [下标]初始化定义
a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; //完整赋值
a[1][2] = {1,2,3,4}; //顺序赋值
a[3][4] = {{1},{2},{3}} //部分赋值
字符串
c语言中字符数组表示字符串,字符数组和一个字符串的区别在于字符串以\0
结尾。这个字符串的结束符编译器会自动加上,无需认为处理。
字符数组也可以直接通过%s
直接输出。
#include<stdio.h>
int main(){char a[10] = {'C','h','i','n','a'};int i;for(i=0;i<10;i++){printf("%c",a[i]);}printf("\n");printf("%s\n",a); printf("%s","China");
}
字符数组逐个字符输出用
%c
,将整个字符串统一输出用格式符%s
。
对于数值型数组,未赋值部分元素默认值未0,对于字符数组未赋值元素默认值为空字符。
注意:
- 在使用字符串输入输出时,输出字符不包括
\0
; %s
输出字符串时,变量时数组名而不是元素名;- 如果数组长度大于字符串实际长度,也只输出到
\0
; - 用
scanf
方法可以输入一个字符串,输入字符长度需小于字符数组长度,且输入项变量不用加地址符,因为数组名就表示数组起始地址。 printf("%d",a)
a为数组,表示输出数组的起始地址。
字符串函数
引入头文件#include<string.h>
函数名 | 描述 |
---|---|
gets(字符数组) | 终端输入一个字符串到字符数组 |
pust(字符数组) | 将一个字符串输出到终端 |
strcat(字符数组1,字符数组2) | 连接两个字符数组 |
strcpy(字符数组1,字符数组2) | 复制字符数组 |
strcmp(字符数组1,字符数组2) | 比较两个字符数组 |
strlwr(字符串) | 将字符数组换成小写字母 |
strupr(字符串) | 将字符数组换成大写字母 |
模块化程序设计
在程序设计中随着代码量的不断增加,单个文件的的结构已不满足需要,因此需要将代码分块,与主业务无关的代码分散到其他文件中,就是模块化编程。
在之前已经介绍了对于工具方法,或者与业务无关的方法,声明为.h
的文件,通过#include "路径地址"
引入到主文件中。
在c语言中基础模块时函数,则不同的模块就是将若干函数分模块。
#include<stdio.h>
#include<string.h>void main(){//函数定义在调用之后,需要在调用之前声明函数 void showName(char a[15]);void conStr(char a[10],char b[10]); printf("%s\n","Hello World");char str1[10] = {'i','a','m','h','e','l','l','o'};showName(str1);char str2 = {'m','e','e','t','i','n','g'};conStr(&str1,&str2);
}//同文件函数的分块void showName(char a[15]){printf("%s\n",a);
}void conStr(char a[10],char b[10]){printf("%s%s\n",a,b);
}
一个c程序可以由一个或者多个程序模块组成,每一个模块作为一个源程序文件;对于较大的程序,不将内容完全放在一盒源程序文件中,而是放在多个若干文件中,由多个源程序文件组成一个完整的c程序。
C语言程序都是以main()
函数开始执行,在mian函数调用其他函数完毕后再回到main函数。
所有函数都是平行的,函数的执行顺序取决于mian函数的调用顺序,函数不能嵌套定义但却可以嵌套调用。
函数可以分为三种:库函数,即系统自带函数,在编译环境中,通过#include<模块名>
引入,之后就可以通过方法名引用。
函数
在c语言中,函数是程序的基本单位,函数必须先定义再调用,函数应包含:函数名,函数值类型,函数的参数名称和类型,函数需要完成什么任务。
函数定义
类型名 函数名(){函数体
}
函数值通过return
关键字返回。
函数调用
函数名()
无参数调用
函数名(实参列表)
有参数的调用,顺序对应。
注意事项
- 函数定义在函数调用之后时,需要在调用前声明,声明即把除函数体的部分在使用前表示即可。(函数定义在调用之前可以不用声明)
- 定义函数的形参,在使用前并未分配内存,在调用函数时将实参传递给形参。
- 通过
return
关键字将函数体得到的值返回给函数,并在调用处使用。 - 调用结束后,形参内存单元被释放。
- c语言的实参传递数据的过程时值传递。
函数声明需要满足,(1)函数必须是以定义了的函数,(2)库函数为需要通过#include<模块名>
引入,且库函数在预编译过程加载,无需声明。自定义函数需要映入加声明。
编译系统并不检查参数名,只检查参数类型,因此参数名并不强制,在声明函数是可以只声明函数类型即可。
函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2 ....);
函数类型 函数名 (参数类型1,参数类型2);
函数定义可以函数声明区别在于函数定义是对函数类型,参数和功能的定义,是一个完整,独立的函数单位;而函数声明只是将定义的函数名,参数类型等定义时函数的一些信息(不包含函数体)通知编译器。
函数的递归调用
在定义一个函数时,直接或间接调用函数本身称为函数的递归调用。
例如,第3个孩子比第2个孩子大2岁,第2个孩子比第一个孩子大2岁,第一个孩子5岁,问第三个孩子几岁?该问题就是一个递归问题。
解决上述问题必须具备两个条件,递推的条件(大2岁)和结束条件(第一个孩子5岁),根据推理:
f(3)=f(2)+2f(3) = f(2) + 2 f(3)=f(2)+2
f(2)=f(1)+2f(2) = f(1) + 2 f(2)=f(1)+2
f(1)=5f(1) = 5 f(1)=5
#include<stdio.h>void main(){int age(int x);int c;c = age(3);printf("%d",c);
}int age(int x){if(x == 1){return 5;}else{return age(x-1) + 2;}}
这里的思路是,首先对于任意变量,都取决于其前一个变量的值,在age函数中,结束条件是1,当不满足时直接返回前一个函数age(x-1)+2,以此地推,那么函数未到达结束条件时的返回值因该是:
age(x)+age(x-1)+2+age(x-2)+2....+age(1)
而有结束条件age(1) =5,那么xi-1=1的变量就可以计算出来了,之后其他函数一次调用直至到x变量。
使用递归函数处理问题的关键在于:1.子规模比原问题的规模小,且规模是有规律的;2.必须要有递归的结束条件。
数组作为参数
用数组元素作为实参可以向形参传递一个数组元素的值,有时需要在函数中处理整个数组元素,可以用数组名作为函数的实参。和Java等语言不同的是,C中数组名代表的是数组的首地址,所以在数组名做实参时只是将首地址传递了。
因此在数组名做函数参数时,需要另外开辟一个存放形参的空间,这是和用变量作为函数参数时不一样的,由于数组名代表数组的首地址,因此在传递时也只传递了数组的首地址,在形参内部需要存储首地址的数组变量,由于变量和形参具有同样的数组首地址,所以它们占用同一存储空间,即它们的值也是相等的。(数组名作为新参时编译器不会检测数组长度因此不必指定长度。具体长度由实参数组长度决定)
#include<stdio.h>
int main(){int c;int a[10]={1,2,3,4,5,6,7,8,9,10};c = sum(a);printf("%d",c);
}int sum(int xxx[]){int sum,i;sum =0; for(i=0;i<10;i++){sum = sum+xxx[i];}return sum;
}
在上述代码中,sum函数的形参为一个数组类型变量,调用时传递了a数组,数组做形参时并不分配内存空间,其具体的值由传入的实参决定,在参传递时,xxx接收了a数组的首地址,由于它们共用一个首地址则可以看作数组名的传递传递的数组的地址为引用传递。xxx和a指向同一数组地址。
数组名代表数组的首地址,在作为参数传递时,传递的时数组地址,为引用传递。
变量的作用域、存储方式和生命周期
定义在函数内部或者作为形参的时局部变量,用完即销毁,定义在主函数或者通过#define
定义的变量为全局变量。
如果需要定义局部变量且在函数调用结束后不消失保留原值,的需要定义静态变量用关键字static
。
auto
函数中的形参和内部的局部变量都是此类,函数在被调用时分配空间,调用结束释放空间,该局部变量也叫自动变量
。关键字auto可以省略。
+static
static
关键字声明变量为静态变量会自动保存上一次调用返回的值。
-
register
register
声明寄存器变量,对寄存器变量的取用速度远高于内存存取变量的速度,提高执行效率,该变量也叫寄存器变量
。 -
extern
extern
关键字声明外部变量的作用域,在一个文件内扩展外部变量作用域,将外部变量的作用域扩展到其他文件。
访问权限控制
extern函数声明外部函数,关键字可以省略,static声明内部和那护士只能在同一源文件使用。
指针变量
一个变量包含两个部分,变量地址和变量的值。c语言中将地址形象化称为指针
,通过指针能快速找到以它为地址的内存单元。引入指针后处理直接访问变量的值外也可以通过地址间接访问变量的值。
指针是C语言的一种特殊变量,用于存放变量的地址。一个变量的地址称为该变量的指针,用来存放地址的变量称为指针变量。
指针的定义*
指针通过*
定义,具体表达式为类型 * 指针变量
;指针指向的是变量的地址,因此需要将变量的地址赋给指针变量。
int *p;
int a= 10;
p = &a;
printf("%d",p);
定义指针变量需要注意的是*
表示该变量是一个指针变量,区别于其他基变量类型;定义指针时必须指定基类型,原因时不同类型的变量的地址所占的内存空间不一样;赋值给指针变量的是地址而不是数据即用&
取地址,指针变量只能取地址。
定义指针变量时
*
表声明类型为指针变量,如 int * p;指针变量是p而不是*p。p = &a;
指针变量的引用
定义指针变量的关键字是*
,除了在定义是起声明作用外,*
在也可以引用指针变量作取值和赋值使用。
*
在定义指针变量时起声明作用,在引用指针变量时起取指针变量指向内存地址的数据
的作用。
&
为取地址符号&a
表示取a变量的地址;*
为指针运算符,*p
为指针变量p指向的对象的值。
#include<stdio.h>int main(){int a = 10;int *p;p=&a;printf("变量的值%d\n",*p);printf("指针初始地址%d\n",p);*p = 100;printf("修改后的值%d\n",*p);printf("赋值后指针地址%d\n",p);}
指针变量做函数参数
指针变量做函数参数是时是将变量的地址传输到另一个函数中,但是不能通过形参的指针指向改变实参的指针指向,只是错误的。
#include<stdio.h>int main(){int a = 10;int *p;p=&a;printf("变量的值%d\n",*p);printf("指针初始地址%d\n",p);*p = 100;printf("修改后的值%d\n",*p);printf("赋值后指针地址%d\n",p);int a1 = 10;int a2 = 100;printf("交换前%d,%d\n",a1,a2);swap(&a1,&a2);printf("swap交换%d,%d\n",a1,a2); swap1(&a1,&a2);printf("swap1交换%d,%d\n",a1,a2); }int swap(int *p1,int *p2){int tmp;tmp = *p1;*p1 = *p2;*p2 = tmp;
} int swap1(int *p1,int *p2){int *tmp;tmp = p1;p1 = p2;p2 = tmp;
}
在上述程序中,swap函数传递两个变量的地址,在函数体中通过*
取出指针变量指向的值来交换数据,这个原理和下面的原理时一致的:
void swap3(int a,int b){int tmp;tmp =a;a = b;b = tmp;
}
但是swap2,企图修改指针指向的地址即通过交换两个指针变量的地址来间接改变变量的值,这是错误的,因为不能通过形参来改变实参的值。(c语言形参的传递都是值传递,对实参复制一份相同的数据分配空间)
指针引用数组
一个数组包含若干元素,在C语言中数组的地址即数组首个元素的地址,c语言底层实现了数组的查找,取值的操作,因此只需要记录数组的首地址即可,编辑器就可以通过特定算法计算其后元素的地址。
int array[] = {1,2,3,4,5};
printf("数组array的地址为%d\n",array);printf("数组array[1]的地址为%d\n",&array[0]);
系统知道数组首地址后可以自动计算其余元素的地址,因此指针变量在操作数组时也只需要记录数组的首地址即可。
C语言中数组的指针就是数值首地址。
int *p = &array[0];printf("%d\n",p);
由于p
指针变量表示&array[0]
即*p = array[0]
,p = &array[0]
,于是得出结论,指针变量是数组首元素的地址,在数组中每个元素同时同一类型,因此占据的内存空间一致,那么p+1
就是array[1]
的地址,一次类推。
当使用指针表示数组是,指针变量表示数组的首地址,指针变量的累加表示地址块的累加,依次表示数组其他元素的地址。
指针运算
上述操作中,涉及到指针运算,指针运算并不是逻辑上的将地址的值加一,而是将数组元素所占的地址加一个字节,如一个int占4字节,指针加一指针所占内存空间就加4个字节。
指针表示字符数组
用字符数组存放一个字符串,然后用数组下标可以访问数组元素,也可以通过%s
直接输出真个字符数组。
也可以同指针指向一个字符串,相对于字符数组更简单,通过指针指向字符串,又编译系统自动分配内存大小。
指针表示字符串时也是将字符串当作字符数组初始,由底层实现,只能初始化赋值。
//定义格式
char *str = "xiaoxu";//错误定义
char *str;
str = "xiaoxu";char *str;
*str = "xiaoxu";
下面两个定义都是错误的,字符串底层是用字符数组,指针只能表示一个字符变量的地址,因此下面两个定义都是错误的。底层实现的方式比一样,只能初始化定义。
指向函数的指针
指针也可以指向函数,称为函数指针。
指针在指向函数时需要声明数据类型 (*指针变量名) (参数列表)
,然后再将指针变量指向函数名。就可以实现指针对函数的引用了。
//定义函数
int max(int a,int b){return a+b;
}
//指针声明
int (*p) (int,int);
p = max;//指针引用函数
int c;
c= (*p)(2,1);
printf("%d",c);
指针数组
如果数组的元素全是指针类型变量,则称为指针数组,指针数组的每一个元素都存放一个地址,相当于指针变量。
如果变量为数组指针,那么对元素的引用就是多重指针**p
。
结构体
结构体
c语言中提供的基类型有时后并不能满足需求,于是提供了用户自定义的数据类型结构体。
结构体定义:
struct student{数据类型 变量;...
};
结构体由strcut
关键字定义,其后紧跟结构体的自定义名称,成员变量为类型和变量名,基于基本类型。成员变量也可以是结构体变量。
结构体定义时也可以同时实例化,在定义结束的分号后追加变量名用,
隔开即可。
//结构体定义
struct Student{char name[20];char sex;int age;
};//结构体初始化定义
struct Student{char name[20];char sex;int age;
} Stu,Stu1;struct Student{char name[20];char sex;int age;
} Stu={"xiaoxu",'m',21};
对结构体变量的引用方式为结构体变量.成员名
。通过.
可以获取结构体变量的各个成员的值,如果成员变量也是结构体,就需要一级一级查找。
结构体类型也可以通过声明的方式定义但是要加上struct
关键字,除了声明式定义外,也可以初始化定义,就像上面代码一样。
#include<stdio.h>//初始化结构体变量定义
struct Student{char name[20];char sex;int age;
} Stu={"xiaoxu",'m',21};int main(){printf("%s",Stu);///声明式结构体变量定义struct Student stu2 = {"zhansan",'m',21} ;printf("%s",stu2.name);
}
结构体数组
结构体变量也可以作为数组的元素,数组元素全是结构体变量的数组称为结构体数组。
结构体数组的定义步骤:
//1、定义结构体
struct Goods{char name[20];float size;
};//2、声明并初始化结构体数组(也可以先声明后初始化)
struct Goods god1[5] ={{"mianbao",0.12}
};
结构体指针
结构体指针就是将指针变量指向结构体的地址。
//定义结构体
struct Student{char name[20];char sex;int age;
};//声明初始化结构体
struct Student stu3={"lisi",'m',21
};
//定义结构体指针变量
struct Student *p;
p = &stu3;
printf("%s\n",(*p).name);
c中
.
的优先级要高于*
因此*p
需要用括号括起来。
在结构体指针中,为了简化(*指针变量).结构体成员
的书写,c语言提供了->
符号表示取值符号用来代替*
和.
简化编写。
(*p).name
=p->name
所以指向结构体的指针变量也可以用通过->
指向结构体成员,也可以指向结构体数组的元素。
结构体变量和结构体指针做参数
将结构体变量作为参数时,可以传递成员变量个数个数据,传递的过程为值传递,将结构体变量的内存空间的所有内容全部传递给形参。也可以使用结构体指针作为参数传递。
//结构体做参数
toString(struct Student stu){printf("Student{name=%s,sex=%c,age=%.2f}",stu.name,stu.sex,stu.age);
}//结构体初始化
struct Student{char name[20];char sex;int age;
} Stu={"xiaoxu",'m',21},stu100;//声明结构体
struct Student stu3={"lisi",'m',21
}; //调用方法传递结构体变量
toString(stu3);
//定义结构体指针//声明结构体
struct Student stu3={"lisi",'m',21
}; //结构体指针做参数
pointerString(struct Student *stu){printf("Student{name=%s,sex=%c,age=%d}\n",stu->name,stu->sex,stu->age);
}//定义指针变量
struct Student *p;
p = &stu3;
printf("%s\n",(*p).name);
pointerString(p);
枚举
当变量的种类确定,只有若干几个可能的值时,可以定义为,枚举,枚举就是将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举类型用enum
关键字enum week(sum,mon,tue,wed,thu,fri,sat);
内部的元素被称为枚举变量或枚举常量。
#include<stdio.h>int main(){enum week{sum,mon,tue,wed,thu,fri,sat};enum week day = mon;switch(day){case sum:printf("sum");break;case mon:printf("mon");break;case tue:printf("tue");break;case wed:printf("wed");break;case thu:printf("thu");break;case fri:printf("fri");break;case sat:printf("sat");break;default : printf("null");}
}
文件操作
文件名C:\Users\xwh\Desktop\master\test.txt
文件类型ASCII
和二进制文件
,ascii码用于存储字符型数据,文件后缀为txt。
文件指针
每个被使用的文件都在内存中开辟了文件信息区,用于存放文件相关信息,文件有关的类型和方法都在stdio.h的头文件中。
文件名类型为FILE
类型,对文件读写需要先打开文件,读写完毕要关闭文件。打开关闭文件的方法是fopen(文件名,使用文件的方式)
;fclose(文件指针)
表示关闭文件。
使用文件的方式 | 描述 |
---|---|
r | ASCII文件只读 |
w | ASCII文件只写 |
a | ASCII文件追加 |
rb | 二进制文件只读 |
wb | 二进制文件只写 |
ab | 二进制文件追加 |
r+ | ascii码文件读写 |
"r","w","a
是最基本的三种方式,在其后面加”b"
表示对二进制文件,不加为ASCII文件即txt文件。"+"
表示即可读又可写。
一般不对FILE类型的变量命名,而是通过FILE指针来操作文件。
文件读写
对文件读写的函数如下:
函数 | 描述 |
---|---|
fgetc(文件指针) | 从该文件读取一个字符 |
fputc(文件指针) | 写一个字符到文件 |
fgets(str,n,fp) | 从文件fp中读取一个长度为(n-1)的字符串,存到字符数组str中 |
fputs(ch,fp) | 把字符写道文件fp中 |
fprintf(文件指针,格式化字符,输出列表) | 格式化输出(字符) |
fscanf(文件指针,格式化字符串,输出列表) | 格式化写入(字符) |
fread(buffer,size,count,fp) | buffer是二进制地址,size是二进制字节数,count是要写多少个字节,fp文件指针 |
fwrite(buffer,size,count,fp) | 同上 |
读写文件时可以在文件的任何位置写入数据,也可以在任何读取数据。c提供了fseek
函数标记文件的位置,就可光标一样的功能。
fseek(文件指针,位移量,起始点)
文件是外部介质上数据的集合,操作系统把所有输入输出数据作为文件来管理。每个文件都必须要又文件路径,文件主干和后缀。c语言中常用文件指针来操作文件。
相关文章:

C程序设计语言基础
机器语言与高级语言 计算机硬件只能够识别电平信号,正电平或负电平,计算机的的各种按钮触发各种电平与计算机交互。随着随着操作系统的发展,人们用1,0分别表示正电平和负电平,并由0,1所组成的一系列指令指…...

构建同一局域网下文件共享网页
首先,我会将这个内容分成以下步骤: 目录 1. 安装必要的软件和工具 2. 搭建本地服务器 3. 编写账号系统和登录页面 4. 实现多人登录 5. 实现文件上传和共享功能 以下是每个步骤的详细说明和代码示例。 1. 安装必要的软件和工具 为了完成这个项目&…...

程序员未来是不是会大量失业?
程序员宝藏库:https://gitee.com/sharetech_lee/CS-Books-Store 会,但是主要原因并不是来自最近爆火的AIGC。 生成式AI对比与传统的工具的确很强大,但是要说替代某种工作岗位还为时尚早。最近铺天盖地的相关推文,热度一波未平又起…...

解密普元大文件传输平台新版本21种特性
本文主要介绍大文件传输平台及其传输特性,以平台版本升级为切入点,探讨大文件传输平台对多种传输场景的支持及部署管控方面能力的增强。目 录01 普元大文件传输平台02 普元文件传输平台新版本特性03 信创项目案例04 总结01普元大…...

每日一问-ChapGPT-20230406-中医基础-脉诊
文章目录每日一问-ChapGPT系列起因每日一问-ChapGPT-20230406-中医基础-脉诊脉诊脉诊的左右手脉诊拓展01沉脉:02迟脉:03促脉:04代脉:05动脉:06短脉:07伏脉:08浮脉:09革脉:10洪脉:11滑脉:12缓脉:13疾脉:14结脉:15紧脉:16芤脉:17散脉:18牢脉:19弦脉:20弱脉:21濡脉:22细脉:23微脉:…...

Nuxt项目asyncData服务端请求数据渲染
或许有些人会比较喜欢在mounted里去请求数据 但在Nuxt项目中是绝对不能这样操作的 因为 mounted的特性也说的比较明白了 当页面挂载完之后执行 但显然 seo只读你页面挂载的内容 如果你在这请求 那么对不起 你请求回来的数据渲染到界面上seo爬虫是看不到的 Nuxt项目请求数据 可…...

Vue 13 - 列表渲染 v-for
V-for介绍 当使用Vue.js框架时,可以使用v-for指令对数据进行循环遍历并渲染到模板中。v-for可以遍历数组、对象、字符串、指定次数等。 以下是v-for的用法: 遍历数组 <div v-for"(item, index) in items" :key"index"> {{…...

XML复习
目录什么是XMLXML中的内容可以干什么XML文件的创建以及其格式XML的文档约束-DTD约数XML的文档约束-schema约束Dom4J 解析XML 文档什么是XML XML 全称(extensible Markup Lanage) 可扩展标记语言它是一种数据的表示形式, 可以存储复杂的数据格式以及我们自己定义的格式.XML经常…...

【python设计模式】10、组合模式
哲学思想 组合模式是一种设计模式,用于将对象组合成树形结构以表示部分-整体层次结构。该模式允许客户端统一处理单个对象和对象组合。 从哲学的角度来看,组合模式可以被视为关于整体和部分之间关系的哲学思想。在这个模式中,整体和部分之间…...

实验五 网络安全加固
目录 一、实验内容 二、实验环境 三、实验步骤 一、实验内容 在GRE VPN实验基础上,对网络进行安全加固。 1、在S0上配置端口安全,设置服务器端口MAC绑定、限制端口MAC连接数量为1,超过最大值则丢弃数据帧。 2、配置OSPF路由协议认证。 3…...

MongoDB综述【入门指南】
写这篇博客,正好是2023年4月5日15:29:31,是清明节,放假一天,我坐在我的小小租房室内,思考着没思考到啥,哈哈哈,感觉好着急啊!看完了一本《城南旧事》,但是就是不踏实,好吧~我来写一篇最近在学的一个技术 为了更优秀的自己~奥利给!! 首先,我们从最初级小白开始(因为自己也是小白…...

Python 3 备忘清单_开发速查表分享
Python 3 备忘清单 Python 3开发速查备忘单是 Python 3 编程语言的单页参考表入门,为开发人员分享快速参考备忘单。 开发速查表大纲 入门 介绍 Hello World 变量 数据类型 Slicing String Lists If Else 循环 函数 文件处理 算术 加等于 f-字符串(Python 3.6) P…...

Thinkphp 6.0模版的加载包含输出
本节课我们来学习一下模版标签中的文件的包含、输出以及加载。 一.包含文件 1. 使用{include}标签来加载公用重复的文件,比如头部、尾部和导航部分; 2. 在模版 view 目录创建一个 public 公共目录,分别创建 header、footer 和 nav…...

ROS实践11 自定义头文件并调用
文章目录运行环境:思路:1.1 编写头文件1.2 includepath添加头文件路径1.3 编写可执行文件1.4 配置文件1.5 编译运行运行环境: ubuntu20.04 noetic 宏基暗影骑士笔记本 思路: 类和函数: 头文件 声明 可执行文件 定义…...

一位年薪35W的测试被开除,回怼的一番话,令人沉思
一位年薪35W测试工程师被开除回怼道:“反正我有技术,在哪不一样” 一技傍身,万事不愁,当我们掌握了一技之长后,在职场上说话就硬气了许多,不用担心被炒,反过来还可以炒了老板,这一点…...

【Docker】Docker常用命令
帮助启动类命令 启动docker systemctl start docker停止docker systemctl stop docker重启docker systemctl restart docker查看docker状态 systemctl status docker[root192 ~]# systemctl status docker ● docker.service - Docker Application Container EngineLoaded…...

【linux基础】7.linux系统自定义应用名和应用图标
"懦弱之人毫无价值"1. 做应用和图标1.1.测试和加入侧边栏3. 命令行重命名唤醒任务叙述:有一个x.sh文件可以在命令行执行,sh x.sh,这样太麻烦。 将其做成app且配上logo,下次直接点击使用将其路径全名重命名,可以直接用重…...

10.网络爬虫—MongoDB详讲与实战
网络爬虫—MongoDB详讲与实战MongoDBMongoDB安装创建数据目录1.数据库操作2.集合操作3.文档操作4.索引操作5.聚合操作6.备份与恢复MongoDB增删改查mongodb集合的增删改查数据插入到表数据的查看删除数据更新数据PyMongo连接数据库第二步 选择需要使用的数据库和集合PyMongo增删…...

C4D -> Three.js资产制作与导入流程
这篇文章介绍从 Cinema 4D 中的 UV 模型到用于 Three.js 的 .glb/.gltf 资产和纹理的整个过程,该网格将依赖 MeshStandardMaterial 来复制你在 Redshift 中看到的内容, 没有由 Three.js 处理的任何照明。 推荐:用 NSDT场景设计器 快速搭建3D场…...

【博学谷学习记录】大数据课程-学习十三周总结
Hive的交互方式 第一种交互方式:bin/hive hive 创建一个数据库 create database mytest; show databases; 第二种交互方式:使用sql语句或者sql脚本进行交互 不进入hive的客户端直接执行hive的hql语句 hive -e “create database mytest2” 或者我们…...

Spring Cloud快速入门
文章目录Spring Cloud快速入门一、基础概念1、微服务架构2、微服务技术栈3、什么是Spring Cloud?4、Spring Cloud和Spring Boot的联系?5、比较成熟的互联网架构二、Rest环境搭建1、搭建提供者1.1、创建一个父工程1.2、创建一个springcloud-api模块1.3、创建一个spr…...

论文学习——VideoGPT
论文学习——VideoGPT: Video Generation using VQ-VAE and Transformers 原文链接:https://arxiv.org/abs/2104.10157 1. 设计思路 不同种类的生成模型在一下多个维度各有权衡:采样速度、样本多样性、样本质量、优化稳定性、计算需求、评估难易程度等…...

Flutter系列(五)底部导航详解
Flutter系列(四)底部导航顶部导航图文列表完整代码,如下: Flutter系列(四)底部导航顶部导航图文列表完整代码_摸金青年v的博客-CSDN博客 目录 一、前言 二、Scaffold组件 三、BottomNavigationBar组件 …...

『pyqt5 从0基础开始项目实战』02. 页面布局设计(保姆级图文)
目录弹性布局介绍导包和框架代码布局框架搭建1. 总体布局框架2. 顶部菜单布局3. form添加内容布局4. table数据展示布局5. footer底部菜单完整项目代码总结欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&am…...

【Python机器学习】——平均中位数模式
Python机器学习——平均中位数模式 文章目录 Python机器学习——平均中位数模式一、Python 平均中位数模式一、Python 平均中位数模式 均值、中值和众数 从一组数字中我们可以学到什么? 在机器学习(和数学)中,通常存在三中我们感兴趣的值: 均值(Mean) - 平均值 中值(M…...

Windows窗口
Windows窗口 Unit01注册窗口类 01窗口类的概念 窗口类是包括了窗口的各种参数信息的数据结构每个窗口都具有窗口类,基于窗口类创建窗口每个窗口都具有一个名称,使用前必须注册到系统 02窗口类的分类 系统窗口类 系统已经定义好的窗口类,…...

Spring Transaction 源码解读
Spring Transaction 规范的maven坐标如下: <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>...</version></dependency>该包提供了spring事务规范和默认的jta(ja…...

[Netty] Channel和ChannelFuture和ChannelFutureListener (六)
文章目录1.Channel介绍2.ChannelFuture接口介绍3.GenericFutureListener接口介绍1.Channel介绍 NIO的Channel与Netty的Channel 不一样 Netty重新设计了Channel接口,并且给予了很多不同的实现, Channel是Netty网络的抽象类, 除了NIO中Channel所包含的网络I/O操作, 主动建立和关…...

条件渲染
组件经常需要根据不同条件显示不同内容。在React中,你可以使用类似于if语句、&&和?:运算符的JavaScript语法有条件地呈现JSX。你将学到:如何根据条件返回不同的JSX如何有条件地包含或排除一段JSX在React代码库中常见的条件语法快捷方式有条件地…...

springboot(10)异步任务
文章目录1、SpringBoot异步任务1.1使用注解EnableAsync开启异步任务支持1.2使用Async注解标记要进行异步执行的方法1.3controller测试2.异步任务相关限制3.1自定义 Executor3.1.1应用层级:3.1.2方法层级:3.2自定义 Executor (第二种方式)4.1异常处理4.1.…...