输入与输出
-
格式控制符 说明 %c 读取一个单一的字符 %hd、%d、%ld 读取一个十进制整数,并分别赋值给 short、int、long 类型 %ho、%o、%lo 读取一个八进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型 %hx、%x、%lx 读取一个十六进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型 %hu、%u、%lu 读取一个无符号整数,并分别赋值给 unsigned short、unsigned int、unsigned long 类型 %f、%lf 读取一个十进制形式的小数,并分别赋值给 float、double 类型 %e、%le 读取一个指数形式的小数,并分别赋值给 float、double 类型 %g、%lg 既可以读取一个十进制形式的小数,也可以读取一个指数形式的小数,并分别赋值给 float、double 类型 %s 读取一个字符串(以空白符为结束)
C 输入
scanf
函数介绍:scanf("%type", &ptr)
-
在VS中,
scanf
将被视为不安全的函数,应当使用scanf_s
。 -
不能读取带空格的字符串,当读到空格时,停止读入。
-
返回值为成功读取的变量个数
-
sscanf(s, "<#format#>", <#address#>);
:从字符串读取。
getchar()
单个字符输入
gets
函数介绍:gets(str)
- 可以读取带空格的字符串。
- 有长度限制的读取字符串:
fgets(str, 10, stdin)
C++ 特有输入
cin >>
遇到空格,Tab,回车结束输入。
⚠️⚠️⚠️特别注意:cin
流将内容存放在缓冲区中,\n
没有被擦除。因此,如果后面跟了getline()
,一定要cin.ignore()
!!!
cin.getline(str, len, end_str)
end_str()
默认为\0
。- 其中的
str
为istream
流中的char[]
,假如输入的是string
类型的数据,需要str.c_str()
处理。
getline(cin, str)
- 其中的
str
为string
流。
C 输出
printf
格式输出
-
%a.bs
:a
为占的字符长度,b
为输出字符串的长度。+
右对齐,-
左对齐。 -
sprintf(s, "<#format#>", <#veriable#>);
输出到字符串
变量与运算
数据类型
(unsigned
) char
, short
, int
, long
, long long int
, bool
, float
, double
,long double
, long long double
, enum
, bool
, pointer
, array
, struct
, union
整型变量
char
, short
, int
, long int
, long long int
, bool
char
类型变量本质上是以ASC- II码的形式存放,也就是说,是一个整数。⚠️注意:char
类型需要使用单引号对,双引号对是char[]
类型。- 八进制:
0__
;十六进制:0x__
。但是int
类型的变量都是以十进制为准的,因此假如给变量赋的值是形如0__
或0x__
(输入的无效)的话,最终就会发生进制转换。 bool
类型需要#include <stdbool.h>
,不是0的都是1.
浮点型变量
- ⚠️注意强制类型转换导致的精度缺失/
float
自动转成double
的情况!!! - 浮点计算结果可能会不准确。
- 一切强制类型转换都用的是去尾法,但是输出流控制可以实现四舍五入。
枚举类型enum
数据类型的最值
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
printf("%d\n",CHAR_MAX);
printf("%d\n",CHAR_MIN);
printf("%d\n",INT_MAX);
printf("%d\n",INT_MIN);
return 0;
}
运算
实例——输出各位数
void num(int x)
{
int i, j;
for (i = 0; i < 8; ++i) //计算x位数
if (x / int(pow(10, i)) == 0)
break;
for (j = 0; j < i; ++j) //提取各位数字(逆序提取)
{
cout << x % 10 << endl;
x /= 10;
}
}
math.h
中的公式
floor(x)
ceil(x)
fabs(x)
log(x)
log10(x)
exp(x)
sqrt(x)
pow(x, y)
- 这些函数都是以
double
类型进行运算,因此最好加上int()
位运算符
~
:按位取反&
:按位取与|
:按位取或^
:按位异或<<
:左移补0/1>>
:右移补0/1
位运算符实例1——x中的第p位开始的n个bit求反
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int x,p,n;
scanf("%u %u %u",&x,&p,&n);
printf("%u",x^(~(~0<<n)<<(p-n+1)));
return 0;
}
选择、循环结构
选择结构
if
switch
switch (<#expression#>) {
case <#constant#>:
<#statements#>
break;
default:
break;
}
switch
实例
#include <stdio.h>
#include <stdlib.h>
int main()
{
int day;
scanf("%d",&day);
switch(day)
{
case 1:printf("Monday");
break;
case 2:printf("Tuesday");
break;
case 3:printf("Wednesday");
break;
case 4:printf("Thursday");
break;
case 5:printf("Friday");
break;
case 6:printf("Saturday");
break;
case 7:printf("Sunday");
break;
default:break;
}
return 0;
}
循环结构
for
- ⚠️注意检查起始值和结束值,最重要的是,到底是
++
还是--
!
while
- ⚠️注意检查跳出循环的条件!
break
- 跳出当前所在的循环
continue
- 中段当前的循环操作,继续下一个循环
实例——辗转相除法求最大公因数
#include <iostream>
using namespace std;
int main()
{
int a, b;
int x1, x2, x0 = 1;
cin >> a >> b;
if (a < b)
swap(a, b);//确保大的数位于左侧被除
x1 = a;
x2 = b;
while (x0 > 0)
{
x0 = x1 % x2;
x1 = x2;
x2 = x0;
} //辗转相除,推荐函数递归
cout << "最大公约数是: " << x1 << endl;
return 0;
}
实例——求子集
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// 本质上,子集中元素的有无是该全集中元素个数的二进制加法计数
int main()
{
int n=0,i=0,j=0,count;
scanf("%d",&n);
for(;i<(int)pow(2,n);i++)
{
printf("{");
count=0; //初始化为0
for(j=0;j<n;j++)
{
if(i&(int)pow(2,j))
{
if(count==0) //0为无,1为有,有就进入判断
printf("%d",j);
else
printf(",%d",j);
count++; //count计数用,每成功打印一个数加1
}
}
printf("}\n");
}
return 0;
}
函数
函数指针
函数指针的例子
#include<stdio.h>
int add(int m, int n)
{
return m+n;
}
int sub(int m, int n)
{
return m-n;
}
main(int argc, char *argv[])
{
int (*p)(int m, int n); //定义了一个函数指针,其中p代表的是存放函数的首地址
int a=70;
int b=13;
p=add; //p指向函数add
printf("%d\n", p(a,b));
p=sub; //p指向函数sub
printf("%d\n", (*p)(a,b));
函数递归
int recursion(int x)
{
if (<#case#>)
{
<#easy-solution#>
}
else
return <#recursion#>
}
递归实例1——阶乘
int jc(int x)
{
if (x == 1)
return 1;
else
return x * jc(x - 1);
}
递归实例2——斐波那契数列
int fi(int x)
{
if (x == 1)
return 0;
else if (x == 2)
return 1;
else
return fi(x - 1) + fi(x - 2);
}
递归实例3——辗转相除法求最大公因数
#include <iostream>
using namespace std;
int GDB(int a, int b);
int main()
{
int a, b;
cin >> a >> b;
cout << GDB(a, b) << endl;
return 0;
}
int GDB(int a, int b) //a = q * b + r
{
if (b == 0)
return a;
else
return GDB(b, a % b);
}
数组与指针
整型数组
-
⚠️注意下标的对应关系,不要越界!!!
-
未知长度的数组的输入
-
int i = 0, temp; while (cin >> temp) { data[i++] = temp; if (cin.get() == '\n') break; }
数组传递函数
int function(int array[], int len);
- 如果对数组没有值的修改,应该使用
const
二维数组
arr[i][j]
-
i
代表的是行,j
代表的是列。 -
二维数组的函数参数传递
int function(int array[][N]);
数组的操作
添加元素到指定位置
void arr_append(int arr[], int len, int target, int target_i)
{
int i;
for (i = len - 1; i > target_i; --i)
arr[i] = arr[i - 1]; //前一个覆盖后一个
arr[target_i] = target; //加入
}
删除指定元素
void del(int arr[], int len, int target)
{
int i, j;
for (i = 0; i < len; ++i)
{
if (arr[i] == target) //线性查找元素
{
for (j = i; j < len - 1; ++j)
arr[j] = arr[j + 1]; //后一个覆盖前一个
break;
}
}
}
实例1——求最长平台
#include <iostream>
using namespace std;
constexpr auto N = 100;
int main()
{
int no_use;
int data[N]{}, temp, i = 0, k = 0, j = 0, max;
int num[N]{}, num_temp = 0;
cin >> no_use;
while (cin >> temp)
{
data[i++] = temp;
if (cin.get() == '\n')
break;
} //输入
for (j = 0; j <= i; j++)
{
temp = data[j];
k = j;
while (k <= i)
{
if (data[k] == temp)
{
num_temp++;
k++;
}
else
break;
}
num[j] = num_temp;
num_temp = 0;
} //记录出现的个数
max = num[0];
for (i = 0; i < j; i++)
{
if (num[i] > max)
max = num[i];
} //比较最大的
cout << max << endl;
return 0;
}
实例1——求最长平台
#include <iostream>
#include <string.h>
using namespace std;
constexpr auto N = 100;
int min(int x, int y)
{
if (x < y)
return x;
else
return y;
}
int main()
{
char num_1[N], num_2[N];
cin >> num_1 >> num_2;
int length_1 = strlen(num_1);
int length_2 = strlen(num_2);
int length_min = min(length_1, length_2);
int num_ans[N]{};
int num_last;
int i, j;
num_ans[0] = ((int(num_1[length_1 - 1]) - '0') + (int(num_2[length_2 - 1]) - '0')) % 10;
num_last = ((int(num_1[length_1 - 1]) - '0') + int((num_2[length_2 - 1])) - '0') / 10;
// 将之前输入的字符串转化为每一位的数字
for (i = 1; i < length_min; i++)
{
num_ans[i] = (num_last + (int(num_1[length_1 - i - 1]) - '0') + (int(num_2[length_2 - i - 1])) - '0') % 10;
num_last = (num_last + (int(num_1[length_1 - i - 1]) - '0') + (int(num_2[length_2 - i - 1])) - '0') / 10;
}
// 计算两数位数相同的那部分的加法结果并将进位记录下来
if (length_1 >= length_2)
{
for (j = i; j < length_1; j++)
{
num_ans[j] = ((num_last + int(num_1[length_1 - j - 1])) - '0') % 10;
num_last = ((num_last + int(num_1[length_1 - j - 1])) - '0') / 10;
}
}
else
{
for (j = i; j < length_2; j++)
{
num_ans[j] = ((num_last + int(num_2[length_2 - j - 1])) - '0') % 10;
num_last = ((num_last + int(num_2[length_2 - j - 1])) - '0') / 10;
}
}
// 多出来的那部分数字记录进去,并且记录进位
if (num_last != 0)
{
num_ans[j] = num_last;
for (int k = j; k >= 0; k--)
cout << num_ans[k];
}
else
{
for (int k = j - 1; k >= 0; k--)
cout << num_ans[k];
}
return 0;
}
排序算法
选择排序
void sort(int arr[], int len)
{
int i, j;
for (i = 0; i < len; ++i)
{
// 初始化最小值
int min = arr[i], min_i = i;
//寻找未排序的最小元素
for (j = i; j < len; ++j)
{
if (arr[j] < min)
{
min = arr[j];
min_i = j;
}
}
//将最小元素移到头部
swap(arr[i], arr[min_i]);
}
}
冒泡排序
void sort(int arr[], int len)
{
int i, j;
for (i = len - 1; i >= 0; --i) //很容易出错的地方!设置了泡泡最终的去处是数组的末尾。
for (j = 0; j < i; ++j) //泡泡的一位位浮起
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
查找算法
线性查找
int search(const int arr[], int len, int target)
{
int i;
for (i = 0; i < len; ++i)
if (arr[i] == target)
return i;
return -1;
}
二分查找
int search(const int arr[], int len, int target)
{
int first = 0, last = len - 1, mid;
while (last != first)
{
mid = (first + last) / 2; //初始化mid
if (arr[mid] > target)
last = mid - 1; //修改尾部(-1去除mid本身)
else if (arr[mid] < target)
first = mid + 1; //修改头部(+1去除mid本身)
else
return mid; //找到了
}
return -1;
}
字符数组char[]
字符串处理函数(#include <string.h>
)
-
strcpy(str1, const str2)
-
strlen(const str)
-
strcat(str1, const str2)
-
strcmp(const str1, const str2)
-
\0
到底存在不存在非常重要,否则将会非法读取内存空间! -
strncpy
,strncat
,strncmp
增加了一个unsigned int
参数来限制长度
C++字符串string
考试按自己想来的用吧,慢点再更新。
指针与数组
⚠️注意:指针一定要记得初始化!!!
指针的运算
+
-
:每次加/减一个数据类型所占空间*
/
:非法运算符==
:同一元素>
<
>=
<=
:判断在内存空间的位置前后。假使两侧的元素不位于同一个数组中,这没有实际意义!++
--
:注意运算先后顺序a = *(p++) <=> a = *p++ <=> a = *p; p++
;a = (*p)++ <=> a = *p; *p += 1
整型指针
- 初始化:
int* p = NULL
- 赋值:
*p = num
/p = &num
- 提取值:
*p
字符串指针
- 初始化:
char* str = NULL
- 赋值:
str = st
/strcmp(str, “<#input_string>”)
- 提取整个字符串:
str
- 提取字符串中的字符:
*str
一维数组指针
- 初始化:
int* p = num
- 数组元素的表示:
*(p + i) <=> p[i]
(此处的[]
的功能自带了寻址的作用)
指向指针的指针
**p
二维数组指针
- 初始化:
int (*p)[j] = num
num[i][j]
的表示方法p[i][j]
*(p[i] + j)
*(*(p + i) + j)
*(p + i)[j]
指针数组
-
初始化:
<#type#> *p[N];
-
应用实例——字符串字典序排序
#include <stdio.h> int main() { char *ptr[N] = {"Pascal","Basic","Fortran", "Java","Visual C"}; for (i=0; i<N-1; i++) { for (j = i+1; j<N; j++) { if (strcmp(ptr[j], ptr[i]) < 0) { temp = ptr[i]; ptr[i] = ptr[j]; ptr[j] = temp; } } } }
命令行参数
int main(int argc, const char * argv[])
动态内存分配
ptr = (*<#type_of_ptr#>) malloc(<#size#>);
ptr = (*<#type_of_ptr#>) calloc(<#num#>, <#size#>);
注意不要忘记释放堆内存,以免内存泄漏:free(ptr);
注意在ptr
内存释放之后接地,以免产生野指针:ptr = NULL;
结构化数据
结构体struct
- 结构体的声明与定义1
struct _struct
{
<#type#> <#name#>;
} struct1, struct2;
- 结构体的定义2
struct _struct struct1; // Definition in C
_struct struct1; // Definition in C++
- 访问结构体元素
structure_variable_name.element_name
- 结构体变量的操作
- 同一个结构体类型/不同结构体的相同数据类型可以相互赋值
- 结构体函数传参
- 结构体组
结构体指针
- 定义结构体指针:
point *ptr
- 访问成员:
(*ptr).xxx
或者ptr->xxx
ptr++
所增加的量是该结构体所有成员所占的空间总和
链表
-
节点类型定义
struct Node { //data members int entry; //节点值 Node *next; //(指针) }
-
节点的使用
int main() { Node *head; //创建新的链表头 head = (Node *) malloc(sizeof(Node)); //为头分配空间 head -> entry = X; //为结点赋值 printf("%d,",head -> entry); head->next = (Node *) malloc(sizeof(Node)); head->next->entry = Y; printf("%d,",head->next->entry); }
共用体 unions
-
定义
union _union { <#datatype#> <#dataname#> }
-
使用与
struct
差不多,但是每次只能使用一个成员
C文件管理
FILE *fp; //初始化定义文件指针
fp = *fopen(<#filename#>, <#mode#>); //返回文件指针,若失败返回NULL。macOS下查询文件目录使用的是pwd指令。
//读取/输出单个字符,fscanf和fprintf也可以
int getc(FILE *fp);
int putc(int c, FILE *fp);
//读取或者输出字符串
char *fgets(char *line, int maxline/*最大字符数量*/, FILE *fp);
int fputs(char *line, FILE *fp);
//⚠️关闭文件指针,一定要记住!!!!!!!
int fclose(FILE *fp);