C/C++基础知识补充笔记

参考书籍:《算法笔记》前两章

变量类型:

  • 整型:109以内或者说32位整数,用int来存放;1018以内或者说用64位整数,用long long来存放,赋初值时要加上LL;

  • 浮点型:用double不要使用float。double输出格式:%f%.1lf指保留一位小数输出;

  • 字符型:ADCII码:0~127。A:65,a:97。字符常量(必须是单个字符),必须用单引号标注。char类型输出格式:%c

    \n:代表换行 \0:代表空字符NULL,ASCII码为0;

    字符串型:string(c++),只能使用字符数组的方式。字符串常量是双引号标记的字符集,输出格式:%s

    不能把字符串常量赋值给字符变量 char c = "abc"是错误的。

  • 布尔型:整型常量在赋值给布尔型变量会自动转换为True(非零)或者False(零)。-1也会转换为True。

符号常量和const常量:

# define pi 3.14(结尾不加分号)

const double pi = 3.14;

define除了可以定义常量,还可以定义任何语句或片段。如# define ADD(a, b) ((a)+(b))

运算符:

/:两个int相除不会得到double,而是会向下取整。

++i和i++:i++是先使用i再将i加1,++i是先将i加1然后再使用i。

条件运算符:是c语言中唯一的三目运算符。 a?b:c 如果a为真,就执行并返回b的结果,如果a为假,就执行并返回c的结果。

位运算符:由于int的上限是231-1,因此常常把无穷大的数INF设置为230-1(1<<30)-1,可以避免两个数相加超过int的情况。 注意:必须加括号,因为位运算符优先级没有算术运算符高。

const int INF = (1 << 30) - 1const int INF = 0x3fffffff

六种位运算符:

运算符含义语法效果
<<左移a<<x整数a按照二进制左移x位
>>右移a>>x整数a按照二进制右移x位
&位与a&b整数a和b按二进制对齐,按位进行与运算
|位或a|b整数a和b按二进制对齐,按位进行或运算
^位异或a^b整数a和b按二进制对齐,按位进行异或运算
~位取反~a整数a的二进制的每一位进行0变1、1变0的操作

scanf输入:

输入字符串(char数组)时:scanf("%s", str);因为数组比较特殊,数组名称本身就代表了这个数组第一个元素的地址,就不需要加上&。

scanf可以按照格式输入:例如scanf("%d:%d:%d",&a, &b, &c);

scanf读入3 4:%d%d,因为除了%c外,对其他格式符的输入是以空白符(空格、tab)作为结束标志,即除了%c会把空格当字符读入,其他情况会自动跳过空格。

字符数组使用%s读入的时候以空格和换行作为结束的标志,%c可以读入空格和换行。

printf输出:

对于double类型,输出格式%f,在scanf中是%lf。其他类型的格式符与scanf中相同。

三种实用的输出格式:

  1. %md

    %md可以使不足m位的int型变量以m位进行右对齐输出,其中高位用空格补齐,本身超过m位就保持原样。

    int a = 123printf("%5d\n", a);
    
  2. %0md

    当变量不足m位时用0补齐。(在某些题中非常实用)

  3. %.mf

    可以让浮点数保留m位小数输出。(适用于题目要求浮点数输出保留XX位小数,或精确到小数点后XX位)。如果要求四舍五入,需要用到round函数。

getchar输入、putchar输出:

getchar用来输入单个字符,在某些scanf使用不便的场合使用,putchar用来输出单个字符。getchar可以存储换行符\n。

typedef:

能给复杂的数据类型起一个别名,在使用中就可以用别名来代替原来的写法。

typedef long long LL;
LL a = 123456789012345

常用math函数(需要math.h头文件):

  • fabs(double x) :double变量取绝对值;
  • floor(double x)、ceil(double x): double型向下取整和向上取整,返回类型为double型;
  • pow(double r, double p):返回r的p次方,结果也为double型;
  • sqrt(double x):返回double类型的算术平方根;
  • log(double x):返回double类型的以自然对数为底的对数,要求对任意底数求对数需要用到换底公式;
  • round(double x):将double型变量x四舍五入,返回类型也是double类型,若要结果int输出时应当强制类型转换;

break和continue语句:

break:退出整个循环

continue:结束当前循环,进入下一次循环

数组:

一维数组:

注意:如果数组大小较大(大概106),需要定义在主函数外,否者会使程序异常退出。

数组就是从某个地址开始的连续若干个位置形成的元素集合。

数组大小必须是整数常量,不可以是变量。未被赋值的元素一般会默认初值为0。

int a[10] = {1, 3, 4, 5, 3, 12, 5, 2, 8, 9};
char str[1000];

//给整个数组赋初值0
a[10] = {0};
a[10] = {};

冒泡排序:

现给一个序列a,其中元素的个数为n,要求按照从小到大的顺序排序。

比较a[j]和a[j+1],如果a[j]大,就交换。整个算法过程共有n-1躺,每趟都从a[0]比较到a[n-1],每趟都选出一个最大的数放到他的最终位置。

冒泡排序的本质是交换,即每次通过交换的方式把当前剩余元素的最大值移到一段,而当剩余元素减少为0时排序结束。

特征: 外层循环每趟使得从右到左逐渐有序

以从小到大排序为例,
第一趟找到最大的数放在最右边。这就是它的最终位置
第二趟又找到当前最大的数放到当前的最右边。现在已经确定了最右边两个数的最终位置
……
第n-1趟就完成了排序

代码实现:

#include <iostream>
using namespace std;

int main(){
    int a[5] = {3, 4, 1, 5, 2};
    
    for(int i = 0; i < 5; i ++ ){	
        for(int j = 0; j < 5 - i; j ++ ){
            if(a[j] > a[j + 1]){
                swap(a[j], a[j+1])
            }
        }
    }
    for(int i = 0; i < 5; i ++ ) printf("%d ", a[i]);	//注意不要加&
    
    return 0;
}

二维数组:

int a[5][6] = {{3, 1, 2}, {3,4}, {}, {1, 2, 3, 4, 5}};	

未赋值元素默认都是0

结果如下:

3 1 2 0 0 0
8 4 0 0 0 0
0 0 0 0 0 0
1 2 3 4 0 0
0 0 0 0 0 0

可以把二维数组当做一维数组的每个元素都是一个一维数组。
补充: 如果数组比较大(大概106级别),需要定义在主函数外面

memset-对数组中的每一个元素赋相同的值:

给数组中的每一个元素赋相同的值:memset函数(需要cstring头文件)和fill函数(需要algorithm头文件)。

建议使用memset函数只赋值0和-1,因为memset使用按字节赋值。
示例:

int a[5];
memset(a, -1, sizeof(a));

字符数组:

1. 字符数组初始化:

char str[5] = {'h', 'e', 'l', 'l', 'o'};
char str[5] = "hello";	//仅限于初始化,其他地方不允许这么赋值整个字符串

注意:通过赋值字符串来初始化仅限于初始化,其他地方不允许直接用整个字符串来赋值!!!

2. 字符数组的输入输出:

scanf对于字符类型有%c%s两种格式(printf同理),%c用来输出单个字符,%s用来输入一个字符串并存在字符数组里。

%c格式能够识别空格和换行并将其输入,而%s通过空格和换行来识别一个字符串的结束。

char str[110];

scanf("%s", str);
scanf("%s", str);

//输入hello world
//输出hello, 因为%s遇到空格结束输入,因此world没有读进来

gets输入、puts输出:

gets用来输入一行字符串(gets识别\n作为输入结束,因此scanf完一个整数后如果要使用gets,需要先用getchar接收整数后的换行符),并存放到一维数组中。

puts用来输出一行字符串,即将一维数组在界面上输出,并紧跟一个换行。

3. 字符数组存放方式

字符数组是有若干个char类型元素组成,字符数组的末端都是一个空字符\0以表示存放的字符串的结尾。 puts和printf就是通过识别 \0 来进行输出的。

注意:

  • int数组没有\0,只有char型数组才有,结束符\0的ASCII码为0
  • 如果不是使用scanf%s格式或者gets函数输入字符串(例如使用getchar),一定要在输入的每个字符串的后面加上\0,否则printfputs输出时会出现乱码。

cstring头文件:

  • strlen(字符数组) :可以得到字符数组中第一个 \0 前面的字符的个数
  • strcmp(字符数组1, 字符数组2):返回两个字符串大小(按照字典序)的比较结果。数组1大就返回一个正整数,数组1小就返回一个负整数,相等返回0。
  • strcpy(字符数组1, 字符数组2):把字符数组2复制给字符数组1(字符数组2在前面),包括结束符\0,在%s输出的时候\0后面的内容不会输出。
  • strcat(字符数组1,字符数组2):把一个字符数组2接到字符数组1的后面。

获取字符串长度的几个函数:

C/C++中 strlen(str)str.length()str.size()sizeof(str)都可以求字符串长度。

  • str.length()、str.size()、sizeof(str)是用于求string类对象的成员函数
  • strlen(str)是用于求字符数组的长度,其参数是char*

sscanf和sprintf:

两者均在cstdio头文件下。sscanf可以理解为string + scanf

char str[100];

scanf(screen, "%d", &n);	//可以理解为把屏幕中的数放到n,从左到右
printf(screen, "%d", n );	//同理,从右到左

sscanf(str, "%d", &n);		//把字符数组str中的内容以"%d"的格式写到n中,从左到右
sprintf(str, "%d", n);		//同理,从右到左

使用sscanf将字符数组中的内容按照格式写入变量

#include <cstdio>

int main(){
    int n;
    double db;
    char str[100] = "2048:3.14,hello", str2[100];
    sscanf(str, "%d:%lf,%s", &n, &db, str2);
    printf("n = %d, db = %.2f, str2 = %s\n", n, db, str2);
    
    return 0;
}

//输出结果:n = 2048, db = 3.14, str2 = hello

使用sprintf将变量按照格式写入字符数组

#include <cstdio>

int main(){
    int n = 12;
    double db = 3.1415;
    char str2[100] = "good", str[100];

    sprintf(str, "%d %.2f:%s", n, db, str2);
    printf("%s\n", str);
    
    return 0;
}

//输出结果:str = 12:3.14,good

函数:

全局变量: 定义在函数外面的变量,在所有程序段内都有效
局部变量: 定义在函数内部,只在函数内部生效,函数结束后局部变量销毁

以数组作为函数参数: 数组作为参数时,第一维不需要写长度,如果是二维数组第二维需要写长度

void test(int a[], int b[][5]){
}

注意: 数组作为参数时,函数中对数组元素的修改能实现对原数组元素的修改,这和普通的局部变量不同


指针:

在c语言中用“指针”来表示内存地址(或者称指针指向了内存地址),若这个内存地址恰好是某个变量的地址,称这个指针指向该变量

在变量前加上取地址符&,就表示变量的地址。指针是一个unsigned类型的整数。

指针变量:

指针变量用来存放指针(或者可以理解为地址)

给指针变量赋值的方式一般是把变量的地址取出来,然后赋给对应类型的指针变量

int* p = &a;

int*是指针变量的类型,p才是用来存储地址的变量名,因此&a是赋给p而不是*p的。对于一个int*型指针变量p来说,p+i是指p所指的int型变量的下i个int型变量(跨越4iByte)。

指针变量支持自增和自减操作,p++等同于p = p + 1

怎么理解呢?
如果a表示一个房间(地址)里的东西(值),
p相当于房间号(地址),*相当于房间的钥匙
然后 *p 就可以打开房间,获得a的值。

对于指针变量来说,把其存储的地址的类型称为基类型。基类型必须和指针变量存储的地址类型相同。

数组a的首地址为&a[0],在c语言中,数组名称也作为数组的首地址使用,有a == &a[0]成立。(a + i ==&a[i]

指针与数组:
数组是由地址上连续的若干个相同类型的数据组合而成的,因此a[0]的地址&a[0]也就是整个数组的首地址。
C语言中,数组名可以作为数组首地址来使用。

两个int型的指针相减,等价于求这两个指针之间相差了几个int。

使用指针变量作为函数参数:

指针类型可以作为函数参数的类型,此时视为把变量的地址传入函数。如果在函数中对这个地址中的元素进行改变,原先的数据就会确实地改变。

使用指针作为参数,交换两个数:

#include <cstdio>

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main(){
    int a = 1, b = 2;
    int *p1 = &a, *p2 = &b;
    swap(p1, p2);
    printf("a = %d\nb = %d", a, b);
    return 0;
}

引用:

函数的参数是局部变量,对局部变量的修改不会影响到外部的变量。
如果需要对外部变量进行修改,可以用指针。

那如果想不使用指针也能修改传入的参数,那就使用引用。(引用不产生副本,而是给原变量起了个别名),对引用变量的操作就是对原变量的操作。

使用引用,只需要在函数的参数类型后面加上个&就可以了。

#include <cstdio>

void swap(int &x){
    x = 1;
}
int main(){
    int a = 100;
    swap(a);
    printf("a = %d", a);
    return 0;
}

注意: 由于引用是产生变量的别名,因此常量不可使用引用


cin和cout:

cin输入不指定格式,也不需要加取地址符&。

而如果想要读入一整行,则需要使用getline函数。

把一整行读入char型数组str[100]中:

char str[100];
cin.getline(str, 100);

string容器则需要用下面的方式输入:

string str;
getline(cin, str);

补充:

浮点数比较:

浮点数在计算机中的存储总是不精确的,因此需要一个很小的数eps来进行修正。一般为10-8const int eps = 1e-8;

圆周率π:由cos(π) = -1可知π = arccos(-1)。因此可以定义
const double Pi = acos(-1.0);

遇到的库函数:

1.在遇到输出图形的题目时

string row = string(n, a);	//row由n个a组成,n整型a字符型

2.gets()方法已经不被PAT编译器支持,采用cin.getline来读取一行字符串。

cin.getline(s,50,'\n');	//s需要是char *或unsigned char *,50表示读入大小(最大),'\n'表示分隔符,可以省略
getline(cin,s);	//s需要是string,需要引入string头文件

cin.getline适合知道读入大小,固定char数组,速度快
getline(cin,s)不需要指定大小,但速度慢、生成的文件大,适合偷懒用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值