C语言基础(上)

简介:适用于快速复习


基本概念

C语言程序执行过程
.c → . i → .s → .o → .out
预编译, 编译, 汇编, 链接click here

,c是源代码,经过编译预处理得到.i文件,.i由C的编译器经过编译得到.s(汇编代码)然后汇编得到目标文件.o文件,编译器一次只能编译一个.c文件成.o文件(二进制代码),当所有.c文件编译成.o之后,通过链接(构建)得到.out文件

关键字 static
静态本地变量是特殊的全局变量,有本地作用域(只能在函数中访问),全局生存期(跳出函数后,该变量仍存在)

队列和栈的区别
队列先进先出,栈先进后出

数据结构有哪几种?
1)集合
2)线性结构:线性表、栈、队列、双队列、数组、串
3)树形结构
4)图

堆和栈的区别
1)堆需要自己通过malloc申请,申请完要释放(否则会产生内存泄露),栈是自动分配,速度较快
2)堆是不连续的内存,栈是一块连续的内存
3)堆的空间一般比较大,栈的空间一般比较小
4)堆的头部用一个字节存放堆的大小,内容由程序员安排;栈在调用函数时,第一个进栈的是主函数下一条指令的地址,然后是函数的各个参数,然后是函数中的局部变量(注意静态变量不入栈)。当本次调用结束时,局部变量先出栈,然后是参数,最后是指令地址,程序有该点继续运行。

全局变量和局部变量在内存中是否有区别?
全局变量储存在静态数据库,局部变量存储在栈。

关键字break和continue的区别
break是结束循环往下走,或者是结束switch(switch不加break,则程序会往下运行),continue是跳出此轮循环,进入下轮循环

指针和数组的区别
1)数组是用于存储多个相同类型数据的集合;指针相当于一个变量,它存放的是其他变量在内存中的地址。
2)同类型的指针变量可以相互赋值,数组不行,只能一个元素一个元素赋值或拷贝。
3)数组在内存中时连续存放的,开辟一块连续的内存空间;指针指向地址的内容在内存中不连续。

冒泡排序的思想?
N个数排序,从前两个数开始进行比较,大的放在后,一直比到最后一个数,最大值放在最后,下一轮循环重复操作,可以少比一轮。

头文件的作用
通过头文件来调用库功能

预处理三种类型
宏定义、文件包括、条件编译

ifndef/define/endif的作用
防止头文件的重复包含和编译。

1.常量、变量定义、输入输出

#include <stdio.h>

int main()
{
    
    
	//常量定义 
	const int Amount = 100;
	//变量定义 
	int a = 0;
	float b = 0;
	double c = 0;  
	
	printf("请输入一个整数和两个小数:");
	scanf("%d %f %lf",&a,&b,&c);
	printf("%d + %f + %lf = %lf\n",a,b,c,a+b+c); 
	return 0;
} 

2.if、switch判断

#include <stdio.h>

int main() {
    
    
	int price, bill;
	printf("请输入价格和票面:");
	scanf("%d %d", &price, &bill);
	if (bill >= price) {
    
    
		printf("商品价格为:%d\n", price);
		printf("找零:%d", bill - price);
	} else
		printf("钱不够");

	int number;
	scanf("%d", &number);
	switch (number) {
    
    
		case 1:
			printf("number = 1\n");
			break;
		case 2:
			printf("number =2\n");
			break;
		default:
			printf("others\n");

	}
	return 0;

}

知识点:continue和break在循环体中的作用,continue会跳入下一轮循环,break会结束循环

3.循环

  • if循环
#include <stdio.h>

int main()
{
    
    
	int a, i;
	scanf("%d", &a);
	for (i = 0; a != 0;i++)
	{
    
    
		a /= 10;
	}
	printf("这个数字有%d位", i);
	return 0;
}
  • while、do …while
#include <stdio.h>

int main() 
{
    
    
	int a, i = 0;
	scanf("%d", &a);
	do 
	{
    
    
		a /= 10;
		i++;
	} 
	while (a != 0);
	printf("这个数字有%d位", i);
	return 0;
}
//**************
//猜数字游戏
//**************
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int main() {
    
    
	int a, count = 0, number;
	srand(time(0));
	number = rand() % 100 + 1;
	printf("请猜数字(1~100):");
	scanf("%d", &a);
	while (number != a) {
    
    
		if (a > number)
			printf("大了\n");
		else if (a < number)
			printf("小了\n");
		count++;
		printf("请猜数字:");
		scanf("%d", &a);
	}
	printf("猜对了!数字是%d,一共猜了%d次", number, count);
	return 0;
}

知识点:随机数、随机种子、while循环

4.函数

  • 辗转相除法求最大公约数(gcd)
//辗转相除法函数定义
#include <stdio.h>

int f_gcd(int m, int n) {
    
    
	int t, gcd;
	if (m < n) {
    
    
		t = m;
		m = n;
		n = t;
	}
	while (t > 0) {
    
    
		t = m % n;
		m = n;
		n = t;
	}
	gcd = m;
	return gcd;
}

int main() {
    
    
	int m, n, gcd;
	scanf("%d %d", &m, &n);
	gcd = f_gcd(m, n);
	printf("%d", gcd);
	return 0;
}

知识点:函数定义

//辗转相除法函数定义
#include <stdio.h>
//声明函数
int f_gcd(int m, int n);

int main() {
    
    
	int m, n, gcd;
	scanf("%d %d", &m, &n);
	gcd = f_gcd(m, n);
	printf("%d", gcd);
	return 0;
}

//函数定义
int f_gcd(int m, int n) {
    
    
	int t, gcd;
	if (m < n) {
    
    
		t = m;
		m = n;
		n = t;
	}
	while (t > 0) {
    
    
		t = m % n;
		m = n;
		n = t;
	}
	gcd = m;
	return gcd;
}

知识点:声明函数

5.数组

#include <stdio.h>

int main() {
    
    
	int a[] = {
    
    1, 3, 5, 7, 9};
	int i;
	for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
    
    
		printf("a[%d]:%d\n", i, a[i]);
	}

	return 0;
}

知识点:sizeof()可以求出变量所占多少字节。

6.指针

#include <stdio.h>

void f(int *p);

int main() {
    
    
	int i = 3;
	printf("&i = %p\n", &i);
	f(&i);
	return 0;
}

void f(int *p) {
    
    
	printf("p = %p\n", p);
}

结果:

&i = 0065FECC
p = 0065FECC

知识点:
1.指针,p的值是变量i的地址0065FECC,*p的值是3
2.%x和%p都是十六进制输出,前者是小写字母,后者是大写字母,专门用来表示地址的。
3.指针运算符& ∗ * ,前者是取地址,后者是取变量(某个地址的变量)
4.指针的作用:用来return多个值,定义的函数只能返回一个变量的值,当多个变量需要返回时,需要用指针,因为用指针修改变量其实是在内存中的地址上修改内容。

#include <stdio.h>

void f(int *p);

int main() {
    
    
	int i[] = {
    
    1, 2, 3, 4};
	int *p = &i;
	printf("&i = %p\n", &i);
	printf("p = %p\n", p);
	printf("*p = %d\n\n", *p);

	p++;
	printf("p = %p\n", p);
	printf("*p = %d", *p);

	return 0;
}

输出结果

&i = 0065FEC0
p = 0065FEC0
*p = 1

p = 0065FEC4
*p = 2

7.字符串处理

#include <stdio.h>

int main() {
    
    
	char str;
	int letter = 0;
	int number = 0;
	int space = 0;
	int cnt = 0;
	printf("请输入一串字符:");
	while ((str = getchar()) != '\n') {
    
    
		if ((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z'))
			letter++;
		if ((str >= '1' && str <= '9'))
			number++;
		if (str == ' ')
			space++;
		cnt++;
	}

	printf("字母%d个,数字%d个,空格%d个,长度为%d", letter, number, space, cnt);
	return 0;
}

知识点:getchar()一次只能读入一个字符,gets()能一次读入一个字符串

#include <stdio.h>

int main() {
    
    
	char str[100];
	printf("请输入一串字符:");
	gets(str);
	printf("长度为%d", strlen(str));
	return 0;
}

知识点:gets()会给字符数组末尾加一个’\0’表示输入结束

8.字符串和字符串数组(字符串指针)

#include <stdio.h>
#include <string.h>

int main() {
    
    
	char *str = "hello";
	char *p ;
	p = strchr(str, 'l');
	//打印出出 llo
	printf("%s\n", p);
	//打印出 l
	printf("%c\n", *p);

	// which one means address?
	printf("%p\n", &p);
	printf("%c\n", *p);
	printf("%p\n", p);

	p++;
	printf("\n");
	printf("%p\n", &p);
	printf("%c\n", *p);
	printf("%p\n", p);

	return 0;
}

结果:

llo
l
0065FECC
l
00404002

0065FECC
l
00404003

知识点:
1.单个字符串定义可以写成char *a,也可以写成char a[],定义的char *a可以当数组来使用。[什么情况不可以互用?看这里]

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    
    
	char str[] = "hello";
	char *p = strchr(str, 'l');

	*p = '\0';

	printf("%s\n", str);
	return 0;
}

2.通过最上面的例子,我们能很好地理解字符串指针。strchr返回的是第一个“l”的地址,p打印出来是llo(%s),*p打印出来是l(%c)。这是因为char *p完全可以当作数组来用,因此打印数组p的结果就是整个数组。
我们再看,p++前后打印p的结果是00404002、00404003,*p打印的结果都是‘l’,说明p是‘l’的地址,p++之后,p指向下一个’l’,故 *p输出都是’l’。
那么&p是什么呢?应该是p的地址。


#include <stdio.h>
#include <string.h>

int main() {
    
    
	char *a[] = {
    
    "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
	int n;
	scanf("%d", &n);
	printf("%s\n", a[n - 1]);
	return 0;
}

知识点:*a[0]、*a[1]…的值是地址值,地址的内容是月份

#include <stdio.h>
#include <string.h>

int main() {
    
    
	char *a = "hello";
	char b[100];

	//string copy
	strcpy(b, a);
	printf("%s %s\n", a, b);
	//string compare
	if (strcmp(b, a) == 0) {
    
    
		printf("相等\n");
	}
	//string length
	printf("字符长度:%d\n", strlen(a));
	//string cat
	printf("字符串拼接%s", strcat(b, a));
	return 0;
}

知识点:字符串复制、拼接、比较、求长度。注意,strcpy,strcat是不安全的,因为不知道被拼接的对象空间是否够,所以用安全版本的函数strncpy,ctrncat,strncmp

9.动态内存分配

#include <stdio.h>
#include <stdlib.h>

int main() {
    
    
	int *p = 0;
	int n = 4;
	p = (int *)malloc(n * sizeof(int));
	int i;
	for (i = 0; i < n * sizeof(int); i++) {
    
    
		printf("%p\n", p[i]);
	}
	free(p);
	return 0;
}

结果

00A42ED8
00A400C0
79705C73
63726F74
0F1AFAD8
0000B9B4
00A400C0
00A43EE0
6C694620
4E5C7365
49444956
50472041
6F432055
7475706D
20676E69
6C6F6F54

知识点:
1.动态内存分配用于不确定长度的数据,malloc类型为void*,需要做类型转换,返回值为申请来的内存地址
2.动态内存分配的内存不连续
3.用完要free(),需要注意的是free()的参数可以是NULL(也就是0),也可以是p,但不能是p++后用free(),因为这free的不是申请来的内存地址,会报错

猜你喜欢

转载自blog.csdn.net/weixin_44823313/article/details/113754672