C语言核心语法

556 阅读4分钟

前序

用来记录C语言学习中的知识点

位运算

  • << 表示左移,不分正负数,低位补0
  • >> 表示右移,如果该数为正,则高位补0,若为负数,则高位补1
  • >>> 表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0

以>>右移为例,

条件编译

指令说明
#无任何定义
#include引用头文件
#define宏定义
#undef取消已定义的宏
#if条件为真则执行
#ifdef存在宏,则执行
#ifndef不存在宏,则执行
#elif相当于java中的elseif
#endif结束条件编译
#include <stdio.h>
//#define NUM1 10
#define NUM2 20
int main() {
	#ifdef NUM1 == 10
		printf("sum %d", NUM1);
	#elif NUM2 == 20
		printf("sum %d", NUM2);
	#endif
	return 0;
} 

理解内存的分配与释放

单链表是动态数据结构,如何开辟一个内存单元呢?通过malloc函数,

(指针类型*)malloc()

返回值为指向新开辟内存单元的首地址

那如何释放内存呢?

通过free可以释放由malloc动态开辟的内存单元,释放后,值是不变的,但是此时内存是无效的,实际例子

#include <stdio.h> 
int main() {
	int *a = malloc(sizeof(int));
	a = 101; 
	printf("a=%d, length=%d",a,  sizeof(a));
	free(a);
	a = 102;
	printf("a=%d, length=%d",a,  sizeof(a));
	return 0;
} 

输出结果为

a=101, length=8

因为此时内存已被释放,所以不能重新赋值了

C语言中的对象-结构体怎么表示

结构体可以可以理解为包含多种不同数据类型的集合,使用方式

struct 结构体名字 {
    结构体所包含的变量和数组
} 结构体变量名字

如何给结构体变量赋值

通过.直接引用,类似java对象的引用

#include <stdio.h> 
int main() {
	struct stu {
		char *name;
		int num;
		char abc;
		float score;
	} stu1;
	stu1.name = "张三";
	stu1.num = 101;
	stu1.abc = 'A';
	stu1.score = 99.6;
	printf("%s的学号是%d, 等级是%c, 成绩是%.1f\n", stu1.name, stu1.num, stu1.abc, stu1.score); 
} 

如何定义结构体数组

以实际demo为例

#include <stdio.h>
struct stus {
	char *name;//姓名
	int num;//学号
	float score;//成绩
} class[] = {
		{"zhangsan", 1, 86.2},
		{"wangwu", 2, 89.5},
		{"zhaoliu", 3, 98.5}
};
int main() {
	float total;
	int i;
	for(i=0; i<3; i++) {
		total += class[i].score;
	}
	printf("平均分为%f", total / 3);
	return 0;
}

输出为

平均分为91.400002

C语言中如何回调(待读)

什么是无符号数

C语言的long、short、int默认是有符号的,通过unsigned无符号数,来定义正数,内存减少了一半,不过对应的输出类型要注意,比如int a=10%d,而unsigned int a = -12,要用%u作为输出

什么是assert断言

assert是<assert.h>的宏定义,用来检查表达式的值是否正确,如果assert内的表达式为假,则终止程序,即不会执行assert后的程序

如何使用

比如

#include <stdio.h>
#include <assert.h>
int main() {
	int a = 0;
	scanf("%d", &a);
	assert(a != 2);
	printf("a=%d", a);
	return 0;
}

如果输入1,则正常执行,输出结果为

1
a=1

如果输入2,则assert会抛出错误并终止程序,输出结果为

2
Assertion failed!

Program: C:\c_projects\assert.exe
File: C:\c_projects\assert.cpp, Line 6

Expression: a != 2

头文件

头文件是命名为.h的文件,包含函数声明和宏定义,头文件分为系统定义的和用户定义的, 系统定义的通过#include <xx.h>引入,表示只能从系统类库目录中检索,用户自定义的通过#include "xx.h"引入,表示 工程当前目录检索

具体例子实现

先定义头文件header_p.h

#define PI 3.14
#define CONS 2
char *get(char *str, int n); 

test.c中引入,

#include <stdio.h>
#include "header_p.h" 
char *get(char *str, int n) {
	int a = 10;
	printf("str=%s, q=%d\n", str, n*a);
}
int main() {
	int a = 6;
	get("这是测试", 2);
	printf("i=%d,PI=%f", a * CONS, PI);
	return 0;
}

输出结果为

str=这是测试, q=20
i=12,PI=3.140000

头文件编译时发生了什么

编译时,并不是分别对两个文件编译,而是将头文件和目标文件合成同一个源代码,然后进行编译

什么是函数指针

一般指针指向整形、字符串等变量,函数指针表示指针指向函数

#include <stdio.h>

int max(int a, int b) {
    return a > b ? a : b;
}

int main() {
    //函数指针
    int (*p)(int, int) = &max;
    printf("请输入数字\n");
    int d, e, f;
    scanf("%d %d %d", &d, &e, &f);
    printf("最大的数字%d", p(p(d, e), f));
    return 0;
}

main函数

通常main函数中可以不用写参数,但是有种格式为

int main(int argc, char *argv[]) 
  • argc 表示命令行中输入的字符串的数量
  • argv[] 表示字符串数组

怎么使用命令行

创建FileTest.c

int main(int argc, char *argv[]) {
    printf("please input %d char\n", argc);
    for (int i = 0; i < argc; ++i) {
       printf("%d arg is %s\n", i, argv[i]);
    }
    return 0;
}

编译运行FileTest.c,右键选择 然后在terminal中输入FileTest.exe a b c

字符串和字符数组

  • 可以将字符串直接赋值给字符数组char arr[10] = "this is a string"
  • 字符串会在最后自动加'\0',所以可作为字符串终止标志

'\0'在ASII码表中是第0个字符,英文名NUL,中文名“空字符”

高级指针

指向指针的指针

i/o操作

联合体