c语言语法参考

hello world:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("hello!\n");
    return 0;
}

变量

1.1 基本变量的声明

//1.1 C语言中一共有这些基本类型的变量
//c语言中有这些数据类型,它们所占的字节数为:
//_Complex相当于double _Complex
printf("_Bool=%ld,short=%ld,char=%ld,int=%ld,long=%ld,long long=%ld,float=%ld,double=%ld,long double=%ld,float _Complex=%ld,double _Complex=%ld,long double _Complex=%ld,void=%ld\n",\
sizeof(_Bool),\
sizeof(short),\
sizeof(char),\
sizeof(int),\
sizeof(long),\
sizeof(long long),\
sizeof(float),\
sizeof(double),\
sizeof(long double), \
sizeof(float _Complex),\
sizeof(double _Complex),\
sizeof(long double _Complex),\
sizeof(void));

定义变量的语法:

int a0;//定义一个整型变量
int a1 = 0;//定义一个整型变量并附初值
int a10, a11, a12;//可以定义声明多个变量,中间用逗号隔开
int a20 = 0b10, a21 = 077, a22 = 0xff; //一次声明多个变量并赋值。0b表示二进制数,0开头表示八进制数,0x开头表示十六进制数
char c0 = 'P';//定义一个char类型的变量
char c1 = 32; //也可以这样赋值,表示字符A的ASCILL码
long L0 = 10L;//定义一个长整型变量。数字后面加l或L表示这个数字是long型的
float f0 = 3.14299;//定义一个浮点数
float f1 = 1.2e-4;//浮点数可以用科学计数法表示,是0.000012
_Complex compl0 = 1+2j;//定义一个复数1+2j,只有c99才支持
//声明变量的修饰符
unsigned int a3 = 0;//定义一个无符号int型变量
register unsigned int a4 = 0;//定义一个寄存器无符号int变量
const int a5 = 0;//定义一个常量
//a5 = 1; 对一个常量赋值将会出现错误
/*变量声明的通用句型是:
储存类别 有无符号 数据类型 变量表列;
auto     signed
static   unsigned
register
extern
static是内部变量,只能在本文件内使用;extern用来声明外部变量,可以在其它文件中;regist用来声明寄存器变量;auto应该是让编译器自己判断该用那种声明
像这样声明变量的时候:int a = 0,默认是:auto signed int a = 0;
*/
//引用其它文件中的变量
extern int A0;//在fun.c中声明了一个变量A0,现在想要在本文件里引用它,应该这样做

运算符的语法:

//算术运算符+,-,*,/,%
printf("1+1=%d, 1.2+1=%f, 1.2e2*0.1=%f, 5/3=%d, 5/3.0=%f, 8%3=%d\n", 1+1, 1.2+1, 1.2e2*0.1, 5/3, 5/3.0, 8%3);//运算结果应该是:2,2.2,12,1,1.666667,2
//>,<,>=,<=,==,!=; 用来比较两个变量是不是大小关系,运算结果是一个布尔型的值。在C语言中,0表示False,非0表示True
printf("%d, %d, %d, %d, %d\n", a20>a21, L0<f1, a3==a4, a3!=a4, 1==1.0);
//&&,||,!; 逻辑运算符,用来给布尔型变量做逻辑运算
printf("%d, %d, %d", (a20>a21) && (L0<f1), 0 || 99, !0);
//&,|,~,异或,<<,>>; 位运算符,按位与,按为或按位非,按位异或,左移,右移
printf("%x, %x, %x, %x, %x\n",0b0101 & 0b1010, 0b0101 | 0b1010, ~0b0000, 0b1111 << 2, 0b1111 >> 2);
//=,+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=
int a = 10+6;//赋值运算符,把10+6的值赋给变量a20
a += 1; //相当于a20 = a20 + 1;,其它的-=, *=... 以此类推
printf("%d\n",a);
//++,--
//++运算符跟在变量之后
a = 0;
printf("%d\n", a++); //输出结果将会是0
//上面两句代码等价于下面三句代码
a = 0;
printf("%d\n", a);
a += 1;

//++运算符在变量之前
a = 0;
printf("%d\n", ++a);
//上面两句代码等价于下面三句代码
a = 0;
a += 1;
printf("%d\n", a);
//--运算符和++运算符用法一样,不介绍了


//表达式0?表达式1:表达式2,如果表达式0的值为0的话则整体为表达式1的值,如果表达式0的值为1的话则整体为表达式2的值
a = 50 > 60 ? 1:0;

强制类型转换的规则:

//强制类型转换
long L1 = 0xffffffff00000000;
int a6 = (int)L1;
printf("把%lx强制类型转换成int,结果是:%x\n",L1, a6);//从高位截断,输出结果应该是0
printf("把%lx强制类型转换成int,结果是:%x\n",~L1, (int)~L1);//从高位截断,输出结果应该是0xffffffff

数组:

int arrys0[10];//声明一个int型数组,数组长度是10。不初始化时,数组中的元素将会是随机的
int arrys1[5] = {1,2,3,4,5};//声明一个int型数组并初始化
printf("%d, %d, %d, %d, %d\n", arrys1[0], arrys1[1], arrys1[2], arrys1[3], arrys1[4]);//输出arrys1中的全部元素。在C语言中,数组的索引从0开始。并且,arrys1[-1]并不会索引到arrys的最后一个元素
arrys1[0] = arrys1[0] + 1;//更改数组中的元素
printf("%d\n", arrys1[0]);
int arrys2[5] = {1,2,3};//只初始化前3个元素,后2个元素会初始化成0
int arrys3[] = {1,2,3,4};//将会初始化成一个长度为4的数组
int arrys4[10] = {0};//声明一个长度为10的数组,并全部初始化成0
int arrys5[2][3] = {{1,2,3},{4,5,6}};//声明一个2*3的数组,两行三列
printf("arrys5的第二行第一列中的元素是%d\n", arrys5[1][0]);//索引二维数组
int arrys6[2][3][4] = {0};//声明一个2*3*4的三维数组,两行三列四层,并且全部初始化成0
char arrys7[] = "hello!";//声明一个字符型数组。注意,这个数组的长度将是7,因为数组的最后一个元素的值是结束符\0
printf("%s,length of arrys7 is %ld\n", arrys7, sizeof arrys7);//以字符串方式输出arrys7

int a = 0;
scanf("%d\n", &a);
int arrys8[a];//在程序中动态指定大小,注意有的编译器不支持这样做

枚举:

enum number{one, two, three, four, five};

结构体:

struct empty_struct{};//定义一个空结构体,里面什么也没有

struct ordinary_struct{//定义一个普通的结构体
	int var0;
	long var1;
	double var2;
};
struct complex_strcut{//定义一个嵌套的结构体
	int var;
	struct ordinary_strct1 sub_struct;
};
struct empty_struct2{}es0, es1, es3;//定义结构体的同时声明结构体变量

struct ordinary_struct1 os1;//声明一个结构体变量,不赋初值
struct ordinary_struct1 os2 = {1, 2, 3.1};//声明一个结构体变量并赋初值
struct ordinary_struct1 os3 = {.var2 = 3.2};//声明一个一个结构体变量,但只部分赋初值
struct ordinary_struct1 oss[10];//定义一个结构体数组,里边有10个ordinary_struct0类型的结构体变量
printf("os1={%d, %ld, %f}, os2={%d, %ld, %f}\n", os2.var0, os2.var1, os2.var2, os3.var0, os3.var1, os3.var2);//引用结构体中的元素

指针:

//先定义一些变量,一会演示的时候要用
int a, b = 0;
int arr[5] = {0};
struct person{//定义一个嵌套的结构体,表示一个人的姓名、性别和生日
	char name[10];
	char country[10];
};

int *p0;//声明一个指针变量
int *p1 = &b;//声明一个指针变量并赋初值,让它指向b
p0 = &a;//稍后赋值,让p0指向a
printf("a=%d, &a=%p, p0=%p, *p0=%d\n",a, &a, p0,*p0);//依次输出:a的值,a的地址,p0的值,p0指向的变量的值,应该有a=*p0, &a=p0
*p0 = *p0 + 1;//p0指向的变量,也就是a,将会加1
printf("a=%d, &a=%p, p0=%p, *p0=%d\n", a, &a, p0, *p0);
p0 = p1;//现在让p0也指向b
printf("b=%d, &b=%p, p0=%p, *p0=%d\n",b, &b, p0, *p0);//依次输出:b的值,b的地址,p0的值,p0指向的变量的值,应该有b=*p0, &b=p0

//指向数组的指针,并通过指针访问数组中的元素
int *p2 = arr;
printf("%d, %d, %d, %d\n", arr[0], arr[1], arr[2], arr[3]);//直接输出数组arr中的第1, 2, 3, 4个元素
printf("%d, %d, %d, %d\n", *(p2), *(p2 + 1), *(p2 + 2), *(p2 + 3));//通过指向数组arr的指针,引用arr中的元素

//指向结构体的指针,并通过指针访问结构体中的元素
struct person tom = {"tom", "US"};//定义一个person类型的结构体变量
struct person *p_person = &tom;//现在让p_person指向tom
printf("name:%s, contry:%s\n", (*p_person).name,(*p_person).country);//通过指针访问结构体中的元素
printf("name:%s, contry:%s\n", p_person -> name, p_person -> country);//也可以用->运算符访问
	
//指向指针的指针
p0 = &a;//先让p0指向a
int **p3;//声明一个指向指针变量的指针变量
p3 = &p0;//现在让p3指向p0,而p0是指向a的
printf("a=%d, &a=%p, p0=%p, &p0=%p, *p0=%d, p3=%p, *p3=%p, **p3=%d, 这里应该有:a=*p0=**p3, &a=p0=*p3, &p0=p3\n", a, &a, p0, &p0, *p0, p3, *p3, **p3);//
//类似的应该可以定义多重指针,比如:
int *********************p4;//也是可以的

//const *p 和*const p
int const *p5 = 0;//可以更改指针指向,但不能更改指针指向的变量的值
int *const p6 = &a;//不能更改指针指向,但可以更改指针指向的变量的值。注意定义的时候必须同时初始化,否则将是个不能修改的野指针
p5 = &a;//可以更改指针的指向
//     *p5 = 1; //但不能更改指针指向的变量的值
//     p6 = p0; //不能修改指针指向
*p6 = 3; //可以更改指针指向的变量的值
printf("p5=%d\n", *p5);
printf("p6=%d\n", *p6);

char *cp0="abc";
char *cp1="def";
char *cp2="ghi";
char *cpp[3]; //指针数组
cpp[0] = cp0;
printf("cpp指向的数组中的第一个指针变量,指向的变量值是:%s\n", cpp[0]); //这里应该输出abc
printf("cpp指向的数组中的第一个指针变量,指向的变量的第一个元素是:%c\n",*cpp[0]); //这里应该输出a

char **pp;
pp = cpp; //*cpp[]和二重指针是等价的
printf("*pp=%s\n",*pp); //等价于输出cpp[0],将会输出abc
cpp[1] = cp1;
printf("*(pp+1)=%s\n",*(pp+1)); //等价于输出cpp[1],将会输出def
printf("*pp=%c\n", **pp); //等价于输出*cpp[0]

共用体:

union empty{};
union ordinay{//定义一个共用体
	unsigned short var0;
	unsigned int var1;
	unsigned long var2;
};
union ordinay o = {.var2 = 0xffffffffffffffff}; //定义一个共用体变量o,并赋初值
o.var0 = 0x0000;
printf("%lx\n", o.var2); //输出将会是0xffffffffffff0000

if语句:

int a = 1;

//语法:if(表达式1) 语句1 else 语句2*/
if (a == 0) printf("a == 0\n"); //只有一句话时可以省略括号

if (a == 0) //常用用法
{
	printf("a == 0\n");
}

if (a != 0) //完整用法
{
	printf("a != 0\n");
}else
{
	printf("a == 0\n");
}

if (a == 0) //嵌套用法
{
	printf("a == 0");
}else if(a == 1)
{
	printf("a == 1");
}else if(a == 2)
{
	printf("a == 2");
}

switch语句:

/*switch(表达式0){
	case 常量1:语句1
	case 常量2:语句2
	...
	case 常量n:语句n
	default:语句n+1
}*/

int a = 1;

switch (a) //switch的标准用法
{
	case 1:printf("a=1\n");
		break; //break也可以不加,但是这样的话后面case里的语句就都会执行
	case 2:printf("a=2\n");
		break;
	default:
		printf("a是别的值\n");
		break;
}

循环语句:

/*
语法:

while(表达式) 语句

do
	语句
while(表达式)

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

//for相当于
语句1
while(表达式1){
	语句3
	语句2
}

*/

//while循环示例
int a = 0;
while (a < 100) {
	a+=1;
}
printf("a = %d\n", a);//a的值现在应该等于100

//for循环示例
for (int i = 0; i < 5; i++) {
	printf("i = %d\n", i);
}
//上面的for语句等价于下面的while语句
int i = 0;
while (i < 5) {
	printf("i = %d\n", i);
	i++;
}

//goto语句
//上面的while语句等价于下面的goto语句
//	int i = 0;
i = 0;
flag0:
if (i < 5) {
	printf("i = %d\n", i);
	i++;
	goto flag0;
}

//break语句和continue语句的区别
for (int i = 0; i < 5; i++) {
	printf("i = %d\n", i);
	if (i == 3) break;//break直接跳出循环
}
for (int i = 0; i < 5; i++) {
	printf("i = %d\n", i);
	if (i == 3) continue;//continue只是跳出本轮循环
}

/*
死循环的三种写法
flag1:goto flag1;
while(1);
for(;;);
*/

函数:

struct person
{
	char name[10];
	char country[10];
};

int main(){

	//调用前应该先声明
	void empty_fun();				//调用函数之前需要先声明函数
	void fun_with_arg(int a);
	void fun_with_args(int a, int b, int c, long d, long e);
	void fun_with_array0(int a[5]);
	void fun_with_array1(int a[], size_t arr_size);
	void fun_with_array2(int a[10][10]);
	void fun_with_array3(int a[][10]);
	void fun_with_struct_arg(struct person);
	int fun_with_return();
	int *fun_return_pointer();
	struct person fun_return_struct();
	
	int array[5] = {0};

	//通过函数名调用函数
	empty_fun();					//调用empty_fun()
	fun_with_arg(666);				//调用fun_with_arg(), 并传入参数666
	fun_with_args(1,2,3,4,5);
	fun_with_array0(array);		//之前声明的array0变量刚好是长度为10的
	//fun_with_array1({3,4,5});		//不能这样传
	fun_with_array1(array, sizeof array / sizeof(*array));		//对传入数组的长度没有限制
	struct person tom = {"tom", "US"};
	fun_with_struct_arg(tom);
	
	//调用有返回值的函数
	printf("fun_with_return()函数的返回值是:%d\n", fun_with_return());//调用有返回值的函数
	printf("fun_return_pointer()函数返回的指针指向的值是%d\n", (*fun_return_pointer()) = 999);

	//把fun_return_struct0()函数返回的结构体输出出来
	struct person a_person = fun_return_struct();
	printf("fun_return_struct0()的返回值是:name:%s, country:%s\n",a_person.name, a_person.country);

	//上面的函数调用都是直接用函数名调用的,下面通过指向函数的指针变量调用函数
	//例1
	void (*fun_p0)(int);//定义一个指向函数的指针
	fun_p0 = fun_with_arg;//现在让fun_p0指向fun_with_arg()
	(*fun_p0)(0);//调用函数fun_with_arg(), 并传入参数0
	//例2
	int (*fun_p1)();
	fun_p1 = fun_with_return;
	printf("%d\n", (*fun_p1)());

	//演示如何将一个函数作为参数传入另一个函数中
	double sqrt(double);
	double integral(double (*f)(double), double a, double b, double dx);
	printf("f(x) = x^2, 在区间(0,1)上的定积分是: %f\n", integral(sqrt, 0, 1, 0.001));//计算f(x) = x^2从0到1的定积分,计算结果应该是0.333333333

}

//有参数的函数
void empty_fun()				//一个没有参数也没有返回值的函数
{
	printf("hello! from empty_fun().\n");
}
void fun_with_arg(int a)		//定义一个函数,传入一个int类型的参数
{
	printf("print from fun_with_arg(), 传入的参数是: %d\n", a);
}
void fun_with_args(int a, int b, int c, long d, long e)//传入多个参数
{
	printf("print from fun_with_args(), 这个函数有五个参数,是: %d, %d, %d, %ld, %ld\n", a, b, c, d, e);
}
//传入数组
void fun_with_array0(int a[5])	//定义一个函数,要求传入一个长度位5的int型数组
{
	printf("print from fun_with_array0, 这个函数接收一个数组,数组中有: ");
	for (int i = 0; i < 5; i++){
		printf("%d, ", a[i]);
	}
	printf("\n");
}
void fun_with_array1(int a[], size_t arr_size)	//不指定数组的大小
{
	printf("print from fun_with_array1, 这个函数接收一个不定长数组,数组中有: ");
	for (int i = 0; i < arr_size; i++)
		printf("%d, ", a[i]);
	printf("\n");
}
void fun_with_array2(int a[10][10])//传入一个二维数组
{
	printf("print from fun_with_array0, 这个函数接收一个二维数组,输出太麻烦,不输出了\n");
}
void fun_with_array3(int a[][10])//不指定二维数组的行数
{
	printf("print from fun_with_array0, 这个函数接收一个不定长的二维数组,输出太麻烦,不输出了\n");
}
//void fun8(int a[10][]){} 这样声明是不合法的,高维维数不能省略
void fun_with_struct_arg(struct person a_person)//传如结构体
{
	printf("print from fun_with_struct_arg(), 传入结构体,name:%s, country:%s\n", a_person.name, a_person.country);
}
//传入函数
//先定义一个函数f(x) = x^2;
double sqrt(double x)
{
	return x*x;
}
//定义一个函数,计算函数f(x)的定积分。调用的时候注意a的值要小于b,这只是个示例程序,不考虑太多情况
double integral(double (*f)(double), double a, double b, double dx){
	double sum = 0;
	if (dx == 0) return 0;//如果dx等于0,就会造成死循环
	for (double x = a; x < b; x += dx) {
		sum += (f(x) + f(x + dx)) * dx / 2;//上底加下底乘高除二
	}
	return sum;
}

/*
C语言中不能指定参数的默认值,也不能定义带可选参数的函数,下面的代码编译是通不过的

int fun3(int a = 0){
	return a;
}
*/

/*有返回值的函数*/

//定义一个函数,返回值是666
int fun_with_return()
{
	return 666;
}
//返回指针指的函数,返回一个指向int类型变量的指针
int *fun_return_pointer()
{
	int a = 666; 	
	int *p = &a; //这样就可以返回局部变量了,不过这可能导致指针到处飞的问题
	return p;
}
/*返回数组的函数
C语言不能直接返回数组,像这样的写法是编译不过的
int[3] fun13(){
	return {1, 2, 3};
}
要返回一个数组,只能通过返回一个指向这个数组的指针间接地返回
*/
int *fun_return_array(int a[])
{
	//int a[] = {1, 2, 3}; 不能返回在函数内部的数组,因为函数执行完之后对应的内存就会被释放
	return a;//返回的数组只能是全局变量中的数组或者是通过参数传递进来的数组
}
//返回一个结构体
struct person fun_return_struct()//c语言中可以直接返回一个结构体变量
{
	struct person tom = {"tom", "US"};
	return tom;
}
//内联函数
inline void fun_inline()
{
	printf("print from inline function.\n");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值