基础语法
理解int main(int argc,char const *argv[])
https://blog.csdn.net/weixin_68123569/article/details/126349348
https://blog.csdn.net/yang_chengfeng/article/details/49406443
malloc函数
-
函数原型:extern void *malloc(unsigned int num_bytes); // 意为分配长度为num_bytes字节的内存块
-
malloc是动态内存分配函数,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址
-
#include<malloc.h>
-
如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
-
malloc函数的返回的是无类型指针,在使用时一定要强制转换为所需要的类型。
-
在使用malloc开辟空间时,使用完成一定要释放空间,如果不释放会造内存泄漏。
-
mallo函数返回的实际是一个无类型指针,必须在其前面加上指针类型强制转换才可以使用
指针自身 = (指针类型*)malloc(sizeof(指针类型)*数据数量) -
int *p = NULL; int n = 10; p = (int *)malloc(sizeof(int)*n);
-
-
free函数: 释放malloc(或calloc、realloc)函数给指针变量分配的内存空间。
前言
从b语言发展 <== BCPL<== FORTRAN
- 程序框架
#include <stdio.h>
int main()
{
return 0;
}
/*多行注释*/
// 单行注释是C99独有的
输入输出
printf("%d", 12+35);
printf("12+35=%d", 12+35);
scanf("%d", &price); // “格式字符串”,&取地址
const int AMOUNT = 100;//常量不可修改
//一次性输入输出多个
scanf("%d %d", &Amount, &price);
scanf("%d, %d", &Amount, &price);
printf("找您%d-%d = %d元。\n", Amount, price, Amount - price);
变量
- eg:int mount, price;
标志符构造规则:子母、数字、下划线,数字不能在第一位。
-
浮点数,定点数
double price; double Amount; //双精度浮点数,float 单精度"%f" scanf("%lf ,%lf", &Amount, &price); int foot = 100*cm/0.3048;//int自动把浮点变成整形 printf("%x", x);//输出为12进制
-
计算:
a = 10; a++ = 10; a = 11; ++a = 12; a = 12; 单目运算符:a*-b ==> a*(-b)
交换变量的值
int a = 6, b = 5, c;
c = a;
a = b;
b = c;
printf("a = %d, b = %d", a, b);
判断
if(){ ;}
else if(){;}
else{;}
=====================
case是一个路牌,不会阻止程序往下继续执行,break才可以。
int type;
scanf("%d", &type);
switch(type) //type是一个表达式
{
case 1:
printf(".\n");
break;
case 2:
printf("..\n");
break;
case 3:
printf("...\n");
case 4:
printf("....\n");
break;
}
-
比较运算符:printf(“%d\n”, 5==3); //输出0
-
例如 != 此类关系运算符的优先级比算数运算符低,比赋值运算符高。 eg:int r=a>; 7 >= 3+4;
eg:6>5>4 运算6>5结果是1,再判断1>4,最终结果是0
-
循环
while(条件){循环体;}
-
do-while 循环
//先进循环体,再判断条件 do{循环体;} while();
-
for 循环
for(i=1;i<n;i++){;}
-
break :打破这个循环
continue :把这一轮没做的步骤放弃直接进入下一轮循环
-
goto 与out连用,goto out 跳到 out 所在的锚点,用于直接跳出多重循环
int main() { int x; int one, two, five; scanf("%d", &x); for ( one = 1; one < x*10; one++ ) { for ( two = 1; two < x*10/2; two++ ) { for ( five = 1; five < x*10/5; five++ ) { if ( one + two*2 + five*5 == x*10 ) { printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, x); goto out; } } } } out: return 0; }
输出n以内的素数
int main(){
int x, n, amount = 0;
scanf("%d", &n);
int i;
for(x=2;x<n;x++){
int isPrime = 1;
for(i=2;i<x;i++){
if(x%i == 0){
isPrime = 0;
break;
}
}
if(isPrime){
amount++;
printf("%d ", x);
if(amount%5 == 0) printf("\n"); //每隔5个数换行
}
}
}
int isPrime(int n)
{
int i, isPrime = 1;
for(i=2;i<n;i++){
if(n%i == 0){
isPrime = 0;
break;
}
}
return isPrime;
}
整数分解正序输出
int main()
{
int x;
scanf("%d", &x);
int mask = 1;
int t = x;
//计算所给x的位数对应的mask值(123对应100)
while(t>9){
mask *= 10;
t /= 10;
}
printf("x=%d, mask=%d\n", x, mask);
while(mask>0){
int d = x/mask;
printf("%d ", d);
x %= mask;
mask /= 10;
}
return 0;
}
最大公约数(辗转相除法)
int main()
{
int m, n, t, sum;
scanf("%d %d", &m,&n);
sum = m*n;
while(n>0){
t = m%n;
m = n;
n = t;
}
printf("最大公约数:%d", m\n);
printf("最小公倍数:%d", sum/m);
return 0;
}
水仙花数(n位正整数每个位上的n次幂之和等于其本身)
int main()
{
int n;
scanf("%d", &n);
int t=1, j=1;
while(j<n){
t *= 10;
j++;
}
printf("%d\n", t);
//遍历10^n-1到10^n
int i;
for(i=t;i<t*10;i++){
int x = i, sum = 0, d;
while(x>0){
d = x%10;
x /= 10;
int k=1;
int b = d;
while(k<n){
b *= d;
k++;
}
//printf("%d\n", b);
sum += b;
}
if(sum == i){printf("%d\n", i);}
}
return 0;
}
数据类型
-
sizeof :
-
是静态运算符(结果在编译时决定)
-
sizeof括号里的运算不会做
long a = 9; printf("%d\n", sizeof(int)); printf("%d\n", sizeof(++a)); printf("%d\n", sizeof(a+1.0)); //判断a+1.0结果的类型但不会做计算 printf("%d\n", a);
-
-
整形
![](https://img-blog.csdnimg.cn/9d5304354c82412ba9b6f7e73cd1f9b2.png#pic_center)
- 数的范围:
![](https://img-blog.csdnimg.cn/f020803fff2a4a0184b6ffecb09d4ce2.png#pic_center)
![](https://img-blog.csdnimg.cn/9eb568930bcb4e7a9d14c415268b1704.png#pic_center)
char c = 255;
int i = 255;
printf("%d %d\n", c, i);
-
unsigned – 无符号整数
unsigned char c = 255; //0-255 int i = 255; printf("%d %d\n", c, i);
![](https://img-blog.csdnimg.cn/4c7e2f4e0422419ba6a64bc045ae0a91.png#pic_center)
-
0 – 八进制 0x – 十六进制
char c = 012; int i = 0x12; printf("%o %x\n", c, i); //八进制、十六进制输出
-
浮点数
%e – 科学计数法表示
float有效位7位, double有效位15位。
- 浮点的范围和精度
printf("%f\n", 12.0/0.0);
printf("%f\n", -12.0/0.0);
float a,b,c;
a = 1.235f; //加f表示float,不加默认double
b = 1.236f;
c = a+b;
if(c == 2.471) printf("相等\n");
else printf("不相等,c=%f\n", c);
-
字符
char a; a = 49; //49代表字符'1' printf("%c\n", a);
char i= 'C'+'a'-'A';
printf("%c", i);
scanf(“%d %c”);//若中间没有空格,那么整数只读到整数结束为止。
- 逃逸字符
printf("123\t456\n");
printf("12\t456\n");
- 类型转换
- 强制类型转换
-
bool
#include <stdbool.h> bool a = 4>5; printf("%d\n", a);
-
优先运算
- 条件运算符
![](https://img-blog.csdnimg.cn/03d0ffdef4b647bbb60f76b3233d2783.png#pic_center)
逗号运算符:i = (3+4, 5+6); //此时i = 11
函数
- 本地变量
一个例子:
int isPrime(int n)
{
int i, isPrime = 1;
for(i=2;i<n;i++){
if(n%i == 0){
isPrime = 0;
break;
}
}
return isPrime;
}
int main()
{
int n;
scanf("%d", &n);
printf("是否质数:%d", isPrime(n));
return 0;
}
数组
-
定义:
int numble[100]; //定义数组 ,100int。
长度为0的数组可以创建但没意义。
一个例题:统计每一种数字出现的次数。
int main() { const int number = 10; int x; int count[number]; int i; for(i=0;i<number;i++){ count[i] = 0; } scanf("%d", &x); while(x!=-1){ if(x>=0 && x<=9){ count[x]++; } scanf("%d", &x); } for(i=0;i<number;i++){ printf("%d:%d\n", i, count[i]); } return 0; }
int a[10] = {0}; //都是0
int a[] = {0,1,2,3,4,5,6,7,8,9}; //单位10
int a[10] = {[1]=2,4,[5]=7}; //位置1为2后面接着4
int main()
{
int a[10] = {0}; //都是0
int i;
for(i=0; i<10; i++){
printf("%d\t", a[i]);
}
return 0;
}
-
sizeof:占据多少字节
int a[10] = {[1]=2,4,[5]=7}; //位置1为2后面接着4 int i; printf("%lu\n", sizeof(a)); printf("%lu\n", sizeof(a[2])); for(i=0; i<sizeof(a)/sizeof(a[2]); i++){ printf("%d\t", a[i]); }
-
数组赋值:
筛选法求素数
int isPrime(int x,int KnownPrime[],int numberOfKnownPrimes)
{
int ret=1,i;
for(i=0;i<numberOfKnownPrimes;i++){
if(x%KnownPrime[i]==0){
ret = 0;
break;
}
}
return ret;
}
int main()
{
const int number = 100;
int prime[number]; //储存所有的素数
prime[0] = 2; //定义第一个素数是2
int count=1,i=3; //从3开始看是否素数
while(count<number){
if(isPrime(i,prime,count)){
prime[count++] = i;
}
i++;
}
for(i=0;i<number;i++){
printf("%d\t", prime[i]);
if((i+1)%5==0) printf("\n");
}
return 0;
}
选择法排序
int main()
{
int a[10];
int i;
int j,min,t;
for(i=0;i<10;i++){
scanf("%d", &a[i]);
}
//交换
for(i=0;i<9;i++){
min = i;
for(j=i+1;j<10;j++){
if(a[j] < a[min])min = j;
}
t = a[i];
a[i] = a[min];
a[min] = t;
}
//输出
for(i=0;i<10;i++){
printf("%d\n", a[i]);
}
return 0;
}
插入一个数字排序
int main()
{
int a[10];
int i;
for(i=0;i<9;i++){
scanf("%d", &a[i]);
}
int x;
scanf("%d", &x);
for(i=0;i<9;i++){
if(x<=a[i]){
int j,t1,t2;
t1 = x;
for(j=i;j<10;j++){
t2 = a[j];
a[j] = t1;
t1 = t2;}
break;
}
}
for(i=0;i<10;i++){
printf("%d\n", a[i]);
}
return 0;
}
3*3的转置数组
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
int T(int a[3][3])
{
int i,j,t;
for(i=0;i<3;i++){
for(j=0;j<i;j++){
t = a[i][j];
a[i][j] = a[j][i];
a[j][i] = t;
}
}
return a[3][3];
}
int main()
{
int a[3][3];
int i;
for(i=0;i<3;i++){
scanf("%d %d %d", &a[i][0],&a[i][1],&a[i][2]);
}
T(a);//转置
for(i=0;i<3;i++){
printf("%d %d %d\n",a[i][0],a[i][1],a[i][2]);
}
return 0;
}
字符串逆序输出
#include <string.h>
void f(char str[])
{
int i,j,t;
for(i=0,j=strlen(str)-1; i<strlen(str)/2; i++,j--){
t = str[i];
str[i] = str[j];
str[j] = t;
}
}
int main()
{
char str[10000];
scanf("%s", str);
f(str);//逆序函数
printf("%s", str);
return 0;
}
统计各种字符个数
void f(char str[])
{
int i,Ec=0, num=0, tab=0, oth=0;
for(i=0;str[i]!='\0';i++){
if((str[i]>='a' && str[i]<='z') || (str[i]>='A' && str[i]<='Z')) Ec++;
else if(str[i]>='0' && str[i]<='9') num++;
else if(str[i]==' ') tab++;
else oth++;
}
printf("%d %d %d %d", Ec,num, tab, oth);
}
int main()
{
char str[10000];
gets(str);
f(str);
return 0;
}
指针
-
取运算的地址:&后必须是个明确的变量(十六进制)
int i=1; int a; printf("%p\n", &i); //取地址 printf("%p\n", &a); //自上向下分配地址
int a[10]; printf("%p\n", &a); //0060FED8 printf("%p\n", a); //0060FED8 printf("%p\n", &a[0]); //0060FED8 printf("%p\n", &a[1]); //0060FEDC
-
指针:
保存地址的变量
int *p=&i; //*表示p是指针,保存i的地址。 int *p,q; //只有p是指针。
void f(int *p)
{
printf("p=%p\n", p);
printf("*p=%d\n", *p);
*p = 26; //通过p的地址改变了p的值
}
//通过指针交换变量
void swap(int *a,int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
int main()
{
int a=2,b=3;
swap(&a,&b);
printf("a=%d b=%d", a,b);
return 0;
}
-
用于有多个返回值的函数
void minmax(int a[], int len, int *max, int *min) { int i; *min = *max = a[0]; for(i=1;i<len;i++){ if(a[i]<*min){*min = a[i];} if(a[i]>*max){*max = a[i];} } } int main() { int a[] = {1,65,21,8,9,6,23,49,56,7,54,32,12,8}; int min,max; minmax(a, sizeof(a)/sizeof(a[0]), &min, &max); //传入地址 printf("max=%d min=%d", max,min); return 0; }
-
结果用指针返回,函数返回运行的状态(返回特殊的不属于有效范围内的值表示出错)。
int divide(int a, int b, int *result) { int ret = 1; if(b==0) ret = 0; else *result = a/b; return ret; } int main() { int a=5, b=2; int c; if(divide(a,b,&c)){ printf("%d", c); } return 0; }
-
在函数参数表中出现数组指的是指针:(一下四种等价) 数组变量是特殊的指针,是常量指针不能两个数组间直接赋值。
- int sum(int*a, int n);
- int sum(int*, int );
- int sum(int a[], int n);
- int sum(int a[], int );
int a[10]; int *p = a; //不需要&取地址符 &a[1]需要的 a = &a[0];
一个例子: void f(int *b) { printf("f b %u\n", sizeof(b)); printf("f b %p\n", b); } int main() { int a[5] = {1,2,3,4,5}; printf("main a %u\n", sizeof(a)); printf("main a %p\n", a); f(a); int x = 5; int *p = &x; printf("*p = %d\n", *p); printf("p[0] = %d\n", p[0]); //p可以看成p[1]数组 return 0; }
-
const 指针:
int *const p = &i; //p是const,即永久指向i的地址。 *p = 20; //可行 p++; //不可行,p不可改变。
const int *p = &i; *p = 20; //不可行,不能通过p给所指的对象赋值。 i = 20; //可行,i不是const。 p = &j; //可行,p可以指向别的变量。
int main()
{
char ac[] = {1,2,3,4,5};
char *p = ac;
printf("%p\n", p);
printf("%p\n", p+1); //char一个字节
int ai[] = {1,2,3,4,5};
int *q = ai;
printf("%p\n", q);
printf("%p\n", q+1); //int四个字节
printf("%d\t", *p+1);
printf("%d\t", ac[1]); //ac[1]与*p+1等价
return 0;
}
指针减法是减的字节数/sizeof()
- 0地址
- 不同类型指针不能相互赋值
字符串
结构
结构类型
- 枚举:
enum color{red, yellow, green};
void f(enum color c)
{
printf("%d\n", c);
}
int main()
{
enum color t = yellow;
scanf("%d", &t);
f(t);
return 0;
}
-
结构体:
struct date{ //声明了一个叫date的结构类型 int month; //成员 int day; int year; }; //记得有分号 int main() { struct date today; today.month = 02; today.day = 14; today.year = 2022; printf("%i-%i-%i\n", today.year,today.month,today.day); return 0; }
- 结构成员可以时不同类型,用.运算符和名字访问。eg:today.month,today时结构成员。
- 结构名字不是地址,要用&取到地址。
struct date{ //声明了一个叫date的结构类型
int month; //成员
int day;
int year;
}; //记得有分号
int main()
{
struct date today;
today = (struct date){2023,03,26}; //转换成该结构
struct date day;
day = today;
printf("%i-%i-%i\n", today.year,today.month,today.day);
printf("%i-%i-%i\n", day.year,day.month,day.day);
return 0;
}
结构中的指针
struct point{
int x;
int y;
};
struct point* getStruct(struct point*);
void output(struct point);
void print(const struct point *p);
int main(int argc,char const *argv[]){
struct point y={0,0};
getStruct(&y);
output(y);//output的参数是一个结构变量,它会输出结构变量的成员变量
output(*getStruct(&y));//*getStruct(&y)相当于返回的是一个结构变量而不是结构变量的指针
print(getStruct(&y));
}
struct point* getStruct(struct point *p){ //定义了一个名为getStruct的函数,该函数接受一个指向point结构体的指针作为参数,并返回一个指向point结构体的指针
scanf("%d",&p->x);//指针所指结构变量的成员
scanf("%d",&p->y);
//printf("%d,%d\n",p->x,p->y);
return p;
}
void output(struct point p){
printf("%d,%d\n",p.x,p.y);
}
void print(const struct point *p){//const代表不改变这个指针
printf("%d,%d",p->x,p->y);
}
结构中的结构
![](https://img-blog.csdnimg.cn/47436dfb478b46bd8cf5c0b9e140a042.png#pic_center)
![](https://img-blog.csdnimg.cn/961a1ef642ae49348e5d5cdfdaeb3e0a.png#pic_center)
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
void printRect(struct rectangle r)
{
printf("(%d,%d),(%d,%d)\n", r.p1.x,r.p1.y,r.p2.x,r.p2.y);
}
int main(int argc,char const *argv[]){
struct rectangle rects[] = { //结构数组struct rectangle rects[],结构中的结构
{{1,2},{3,4}},
{{5,6},{7,8}}
};
int i;
for(i=0;i<2;i++){
printRect(rects[i]);
}
}
联合
typedef union{
int i;
char ch[sizeof(int)];
}CHI;
int main()
{
CHI chi;
int i;
chi.i = 1234; //0x04d2是1234的16进制树
for(i=0;i<sizeof(int);i++){
printf("%02hhx\n", chi.ch[i]); //%02hhx输出的16进制字节
}
}
全局变量
静态本地变量(全局生存期,本地作用域)
编译预处理和宏和头文件
带函数的宏
头文件
#ifndef _MAX_H_ //避免重复定义
#define _MAX_H_
#endif
可变数组
const BLOCK = 20;
typedef struct {
int *array;
int size;
}Array; //自己创建的可变数组,大小和一个指针(用于储存数据)
Array array_creat(int init_size);//创建可变数组
void array_free(Array *a);
int *array_size(const Array *a);
int *array_at(Array *a,int index);
void array_inflate(Array *a,int more_size);
Array array_creat(int init_size)
{
Array a;
a.size = init_size; //数组a的大小
a.array = (int*)malloc(sizeof(int)*a.size);
return a;
}
void array_free(Array *a)
{
free(a->array);//释放指针a指的数组
a->array=NULL;
a->size=0;
}
int *array_size(const Array *a)//封装
{
return a->size;
}
int *array_at(Array *a,int index)
{
if(a->size<=index)
array_inflate(a,(index/BLOCK+1)*BLOCK-a->size);
return &(a->array[index]);
}
void array_inflate(Array *a,int more_size)
{
int *p=(int *)malloc(sizeof(int)*(more_size+a->size));
int i;
for(i=0;i<a->size;i++)//将之前的值逐一拷贝
{
p[i]=a->array[i];
}
free(a->array);
a->array=p;
a->size+=more_size;
}
int main()
{
Array a = array_creat(100);
printf("%d\n", array_size(&a));
*array_at(&a,0) = 10;
printf("%d\n", *array_at(&a,0));
int number=0;
int cnt=0;
while(number != -1){
scanf("%d",&number);
if (number!=-1){
*array_at(&a,cnt++)=number;
}
array_free(&a);
}
return 0;
}