C/C++的学习笔记(基础部分)

12 篇文章 0 订阅
1 篇文章 0 订阅

C/C++的学习

一.总结

      C语言的应用十分广泛、灵活性强,同时它也比较基础,很适合一些刚入门的
  小白学习,若有了C语言的基础,再去学习其他的语言也会轻松很多。我也是一名
  小白,真正入门技术也才半年的时间,这半年的时间里我学习了很多关于技术方面
  的知识,也自己尝试或与他人合作设计完成过一些小的项目(日后也会更新到我的
  博客中)......
      这段时间,我主要在学习C++,由于C语言的基础部分和C++的极其类似,所以
  我在学习C++的同时,相当于复习了一遍C语言。我也重新整理了一份笔记,希望我
  也可以给大家带来一点帮助。
      笔记中有错误的地方,欢迎指出,欢迎大家讨论!

二.C/C++的基础部分

1.C++ 的框架:
#include <iostream>
using namespace std;

int main
{

	system("pause");
	return 0;
}

C语言的框架:

#include <stdio.h>

int main
{
	return 0;
}

2.C++ 的输入输出:

输出:C++:cout << "a = " << a << endl;(输出变量a的值)

C语言:printf("a=%d",a);(输出变量a的值)

输入:C++:cin >> a;(输入变量a的值)

C语言:scanf("%d",&a);(输入变量a的值)


3.变量类型:

变量存在的意义:方便我们管理内存空间

整型:

变量类型关键字字节大小取值范围
短整型short2字节-215~215
整型int32位 2字节 64位 4字节-231~231
长整型longWindows 4字节 Linux 32位 4字节 Linux 64位 8字节-231~231
长长整型long long8字节-263~263

浮点型(实型):

变量类型关键字字节大小有效数字位数
单精度浮点数float4字节7位有效数字
双精度浮点数double8字节15~16位有效数字

注意:在C++中使用 float 定义一个变量时,往往要加上一个 "f",告诉编译器这是一个 float 类型的变量,因为编译器会默认小数类型是 double 的。

如下所示:

float f1 = 3.14f;  //使用float定义一个变量f1,3.14后面得带上一个f

double d1 = 3.14;  //使用double定义一个变量d1

字符型:(单个字符)

变量类型(关键字)字节大小取值范围
char1字节-128~127

使用语法:char ch = 'a';

如何求某个字符对应的 ASCII 码?

char ch = 'a';
cout << (int)ch << endl;  //将字符型变量强行转化为整型输出

注意事项:

1.要使用单引号,而不是双引号;

2.单引号里面只能是单个字符,不能是字符串;

3.字符型变量并不是把字符本身放到内存中存储,而是将对应的 ASCLL 码放入到存储单元。


字符串型:

使用语法:C语言:char str[] ="......";

C++:

1.C++ 的字符串同样可以使用C语言风格的表示方式;

2.C++ 特有的表示方式:string str = "......";

但使用C++风格字符串时,得包含一个头文件 #include <string>


布尔类型(bool):

真:true(本质是"1");

假:false(本质是"0");

bool flag_1 = true;

cout << flag_1 << endl;  //输出数字1

bool flag_2 = false;

cout << flag_2 << endl;  //输出数字2

布尔类型的变量在输入时,不可以输入 true false,只可以输入数字。实际上,非0的正数其实都代表真,只有0代表假。


4.++-- 的用法

++:I.前置递增:++a 先让变量+1,后进行表达式的运算;

​ II.后置递增:a++ 先进行表达式的运算,后让变量+1;

int a2 = 10;
int b2 = ++a2*10;

cout << "a2= " << a2 << "b2= " << b2 << endl;  //a2=11,b2=110;

int a3 = 10;
int b3 = a3++*10;

cout << "a3= " << a3 << "b3= " << b3 << endl;  //a3=11,b3=100;

--:I.前置递减:–a 先让变量-1,后进行表达式的运算;

​ II.后置递减:a-- 先进行表达式的运算,后让变量-1;

int a4 = 10;
int b4 = --a4*10;

cout << "a4= " << a4 << "b4= " << b4 << endl;  //a4=9,b4=90;

int a5 = 10;
int b5 = a5--*10;

cout << "a5= " << a5 << "b5= " << b5 << endl;  //a5=9,b5=100;

5.程序流程结构:顺序结构、选择结构、循环结构;

顺序结构:程序按顺序进行,不发生跳转;

选择结构:根据条件,有选择的执行代码;

单行 if 条件语句:

if (条件)
{
	....
}

多行 if 条件语句:

if (条件)
{
	....
}
else
{
	....
}

多条件 if 语句:

if (条件1)
{
	....
}
else if (条件2)
{
	....
}
else if (条件3)
{
	....
}
else
{
	....
}

嵌套 if 语句:

if (条件1)
{
	if (条件2)
	{
		if(条件3)
		{
			....
		}
	}
}

三目运算符:. . . . ? . . . . : . . . .

三目运算符相当于一个 if-else 语句,问号前面是条件;问号后面、冒号前面是,条件满足时返回的值;冒号后面是,条件不满足时返回的值;并且在C++中,三目运算符返回的是变量,是可以继续赋值的。

(a > b ? a : b) = 100;

//若a>b,则返回a,即a=100;
//若a<b,则返回b,即b=100;

switch-case 语句:

switch ( /*只可以放整型或字符型*/ )
{
	case 1 : ....
	break;  //若没有break,每个case都会执行一遍
        
	case 2 : ....
	break;
        
	case 3 : ....
	break;
        
	default : ....  //前面的分支都不满足时,走这个default
    break;
}

循环结构:根据条件,循环执行某一段代码;

while 循环:

while (循环条件)
{
	....
}

在执行循环语句的时候,程序必须提供退出的窗口,否则会陷入死循环。

do-while 循环:

while 循环的区别:先执行一次循环语句,再进行循环条件的判断;

do
{
	....
}
while (循环条件);

for 循环:

优点:结构清晰,比较常用,并且在数组初始化和数组遍历上用的会比较多;

for (初始化表达式;循环条件;末尾循环体)
{
	....
}

嵌套循环:

外层循环执行一次,内层循环执行一周;

int i,j;

for(i=0;i<10;i++)  //外层循环
{
	for(j=0;j<10;j++)  //内层循环
	{
		....
	}
}

6.跳转语句:break、continue、goto

break 常用的地方:1.switch-case 语句;2.跳出某个循环;3.跳出内层循环;

break :只对它所在的那层循环起作用

continue:跳过这一轮循环剩下的语句,进入下一轮循环;

goto:无条件跳转语句;

MENU:....

goto MENU;  //goto语法:goto 标记;(标记一般是一个大写的单词)

程序中一般不建议使用 goto 语句,以免造成程序流程混乱;


7.随机数
#include <ctime>  //下面使用随机数种子,得用到这个头文件

srand((unsigned int)time(NULL));  //添加随机数种子,利用当前系统时间生成随机数,防止随机数每一次都一样

int random = 0;
random = rand();  //随机生成一个数字,位数也是随机的
random = rand()%50;  //生成0~49的随机数
random = rand()%100;  //生成0~99的随机数
random = rand()%100+1;  //生成1~100的随机数

8.数组:

数组是一个集合,存放了多个相同数据类型的元素,并且它储存在一段连续的内存空间里。

一维数组:

一维数组定义方式:

1.数据类型 数组名[数组长度];

2.数据类型 数组名[数组长度] = {....};(数组的集成初始化)

如果一开始大括号里面的数据的个数小于数组长度,编译器会用0进行填充;

3.数据类型 数组名[] = {....};

编译器会根据大括号里面有多少个数据来推测数组长度是多少;

int i = 0;
int arr[5] = {1,2,3};  //数组长度为5,大括号里面只有3个数字,即数组中最后两个位置被填充为0

//一维数组遍历
for(i=0;i<4;i++)  //数组的下标从0开始,如:arr[5],第一个是arr[0],最后一个是arr[4]
{
	cout << arr[i] << endl;
}

一维数组名的用途:

1.统计整个数组在内存中的长度;

2.可以获取数组在内存中的首地址;

//一维数组名用途一:统计整个数组在内存中的长度
int arr[5] = {1,2,3,4,5};
int len = 0;  //代表数组的长度

sizeof(arr)  //数组在内存中的长度;由于是int类型,占4字节,且数组长度为5,所以sizeof(arr)=4*5=20
sizeof(arr[0])  //第一个(每个)元素在内存中的长度
len = sizeof(arr)/sizeof(arr[0]);

//一维数组名用途二:可以获取数组在内存中的首地址
cout << arr << endl;  //可以直接输出数组arr的首地址
cout << &arr[0] << endl;  //这种方法也同样可以得到数组arr的首地址,但要带上&(取地址)符号,因为直接arr[0]是输出1的 

二维数组: 行x列 矩阵

二维数组定义方式:

1.数据类型 数组名[行数][列数];

2.数据类型 数组名[行数][列数] = {{....},{....}};

3.数据类型 数组名[行数][列数] = {....};

4.数据类型 数组名[][列数] = {....};

可以省去行数,但不可以省去列数;提供了列数和大括号里面的数字,编译器可以帮你数好行数;

//用四种定义方式分别定义一个2行3列的数组

int arr[2][3];  //定义方式一

int arr[2][3] =  //定义方式二(最直观的定义方式)
{
	{1,2,3},
	{4,5,6}
};

int arr[2][3] = {1,2,3,4,5,6};  //定义方式三

int arr[][3] = {1,2,3,4,5,6};  //定义方式四

//二维数组遍历
int i,j = 0;
for(i=0;i<2;i++)  //常规的二维数组遍历
{
	for(j=0;j<3;j++)
	{
		cout << arr[i][j] << endl;
	}
}

for(i=0;i<2;i++)  //按照矩阵的样子打印二维数组
{
	for(j=0;j<3;j++)
	{
		cout << arr[i][j] << " ";
	}
	cout << endl;  //排完一行打印一个换行
}

二维数组名的用途:

1.查看二维数组所占的内存空间;

2.可以获取二维数组在内存中的首地址;

//二维数组名用途一:
int arr[2][3] =
{
	{1,2,3},
	{4,5,6}
};
int line_num,list_num = 0;  //代表二维数组的行数和列数

sizeof(arr)  //数组在内存中的长度;由于是int类型,占4字节,且该二维数组为2行3列(2*3=6),所以sizeof(arr)=4*6=24
sizeof(arr[0])  //可以查看二维数组第一行(每一行)所占用的内存空间
sizeof(arr[0][0])  //可以查看二维数组第一个(每一个)元素所占用的内存空间

line_num = sizeof(arr)/sizeof(arr[0]);
list_num = sizeof(arr[0])/sizeof(arr[0][0]);

//二维数组名用途二:
cout << arr << endl;  //可以直接输出二维数组arr的首地址
cout << arr[0] << endl;  //二维数组第一行的首地址也是二维数组的首地址
cout << &arr[0][0] << endl;  //二维数组的第一个元素的地址

数组中的经典案例:元素逆置

int arr[5] = {1,3,2,5,4};  //给定的初始的数组,任务要求是将这个数组的所有元素都逆置,即最后要输出4,5,2,3,1

int len = sizeof(arr)/sizeof(arr[0]);  //数组长度
int start = 0;  //起始位置
int end = len-1;  //末尾位置
int temp = 0;  //临时变量

while(end>start)  //正常情况下,末尾位置一定大于起始位置,如果起始位置与末尾位置重合,说明已经完成了所有元素的逆置
{
	temp = arr[start];
	arr[start] = arr[end];
	arr[end] = temp;
	start++;
	end--;
}

//while的那一段代码还可以换成下面这段代码
int i = 0;
for(i=0;i<len/2;i++)
{
    temp = arr[start+i];
    arr[start+i] = arr[end-i];
    arr[end-i] = temp;
    if(start>=end)  //再做一次判断,start>=end时退出循环
    {
        break;
    }
}

//遍历打印
for(i=0;i<5;i++)
{
    cout << arr[i] << endl;
}

冒泡排序(BubbleSort):

1.比较相邻的两个元素,如果第一个比第二个大,就交换它们两个;

2.对每一对相邻元素做相同的工作,执行完毕后,找到一个最大值;

3.重复以上的步骤,每次比较的次数减一,直到不再需要进行比较;

总结:排序总轮数 = 数组中的元素个数 - 1;

每轮比较的次数 = 数组中的元素个数 - 排序轮数 -1;

//冒泡排序(BubbleSort):

int arr[9] = {4,2,8,0,5,7,1,3,9};  //给定的初始数组,现在是乱序,经过冒泡排序后会升序打印数字
int i,j =0;

for(i=0;i<9-1;i++)
{
	for(j=0;j<9-i-1;j++)
	{
		if(arr[j]>arr[j+1])
		{
			int temp = arr[j];
		 	arr[j] = arr[j+1];
			arr[j+1] = temp;
		}
	}
}

//遍历打印:
for(i=0;i<9;i++)
{
	cout << arr[i] << endl;
}

执行流程和效果:

原来的数组:4 2 8 0 5 7 1 3 9

排序轮数4 2 8 0 5 7 1 3 9对比次数
02 4 0 5 7 1 3 8 98
12 0 4 5 1 3 7 87
20 2 4 1 3 5 76
30 2 1 3 4 55
40 2 1 3 44
50 1 2 33
60 1 22
70 11

9.函数

作用:将一段经常用的代码封装起来,较少地重复代码,保证代码质量;

一个较大的项目(程序) ———> 若干个“块” ———> 每一个块用一个函数封装起来


函数定义:

1.返回类型;2.函数名;3.参数列表;4.函数体语句;5.返回值表达式 return

返回类型 函数名(参数列表)
{
	函数体语句
	return 表达式;
}

函数调用:函数名 (参数列表);

调用函数的时候,实参的值会传递给形参;换句话说,调用函数的时候发生的是值的传递,形参发生任何改变,都不会影响实参。

函数常见样式:1.无参无返;2.有参无返;3.无参有返;4.有参有返;


函数声明:返回类型 函数名(参数列表);

1.函数声明要在函数定义上面,且要保证函数声明和函数定义中涉及的返回类型、数据类型保持一致

2.函数声明可以写多次,但是函数定义只能写一次;

3.若函数太多,定义在 main 函数前面会影响整体代码的结构以及可读性,此时可以用到函数声明;

4.写大型程序时,函数声明往往会放在一个 .h 的头文件,而函数定义往往放在一个 .c 的源文件;


10.指针

作用:通过指针间接访问内存(地址),然后对对应内存地址上的变量做访问或修改的操作;

语法:数据类型 * 指针变量名;

指针前加 * 表示解引用,可以找到指针指向的内存中的数据;

指针所占内存空间:C++ 中,32位操作系统,指针变量统一占用4个字节;64位操作系统中,指针变量统一占用8个字节;

int a = 10;
int * p = &a;

cout << sizeof(int *) << sizeof(char *) << sizeof(double *) << endl;  //输出均为4(32位操作系统)

空指针:指针变量指向了内存中编码为0的地方

语法:int * p = NULL;

用途:可以用于初始化指针变量;但空指针指向的内存空间是不可以访问的(0~255位为系统占用,均不可以访问);


野指针:指针变量指向了非法的内存空间

没有申请内存空间,就直接让一个指针指向这个地方,或者这个指针指针指向了我们权限之外的地方;


const 修饰指针:

//事先给定的情况
int a = 10;
int b = 10;
int * p = &a;

1.常量指针:const int * p = &a;(相当于 const 修饰 *p

特点:指针的指向可以改;但是指针所指向的值不可以改,换句话说,不可以通过指针去修改那个值(但对变量做赋值操作是可以的);

p = &b;  //可以
*p = 20;  //不可以
a = 20;  //可以

2.指针常量:int * const p = &a;(相当于 const 修饰 p

特点:指针的指向不可以改,但可以通过指针去修改指针所指向的值;

p = &b;  //不可以
*p = 20;  //可以

3.既修饰指针,又修饰常量:const int * const p = &a;

特点:指针的指向不可以改,也不可以通过指针去修改指针指向应的值;

p = &b;  //不可以
*p = 20;  //不可以

指针和数组:利用指针访问数组中的元素

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int * p = arr;  //一维数组名用途二
int i = 0;

for(i=0;i<10;i++)
{
	cout << *p << endl;
	p++;  //指针往后移一位,指向数组中下一个元素
}

指针和函数:

1.值传递:形参的变化不会引起实参的变化;

2.地址传递:可以通过指针修改实参;


11.结构体

结构体是用户自定义的数据类型,允许用户储存不同的数据类型;

语法:struct 结构体名 {结构体成员列表};

struct 结构体名
{
	结构体成员列表
};

创建结构体变量的方法:

//假设创建一个学生的结构体

struct student
{
	string name;  //姓名
	int age;  //年龄
	double score;  //分数
}s3;  //第三种:定义结构体时顺便创建变量

struct student s1;  //第一种

struct student s2 = {"张三",18,95}

C++struct 关键字可以省略(仅在创建结构体变量时,定义结构体时不可以省略)


结构体数组:struct 结构体名 数组名[元素个数] = {{},{},{}....};

结构体指针:通过指针访问结构体变量

//假设创建一个学生的结构体
struct student
{
	string name;  //姓名
	int age;  //年龄
	double score;  //分数
};

struct student s;  //创建结构体变量
struct student * p = &s;  //创建结构体指针,并指向结构体变量s

//通过.和->访问结构体的成员
cout << s.name << s.age << s.score << endl;  //结构体变量或结构体数组用.访问结构体变量中的成员
cout << p->name << p->age << p->score << endl;  //结构体指针用->访问结构体变量中的成员

结构体嵌套结构体

struct student  //学生的结构体
{
	string name;  //姓名
	int age;  //年龄
	double score;  //分数
};

struct teacher  //老师的结构体
{
	int id;  //编号
	string name;  //姓名
	struct student stu[5];  //带的5名学生;由于老师的结构体里面嵌套了学生的结构体,因此学生结构体的定义要在老师上面
};

struct teacher t;  //创建变量t
t.stu[i].name  //访问

结构体中使用 const 的场景:

作用:用 const 防止误操作;

将函数的形参改为指针(形参中:结构体变量修改为其所对应的指针),可以减少内存空间,而且不会复制出很多新的副本数据出来;但地址传递是可以修改实参的,如果我并不想修改实参,却又在函数中有了误操作,且我还想利用指针减少内存,此时就可以用 const

....(struct student s);

....(struct student * s);

....(const struct student * s);  //若在函数里面一旦有修改操作(针对struct student * s),编译器都会报错

12.内存分区:代码区、全局区、栈区、堆区

代码区:存放函数体二进制代码,由操作系统管理;(代码区两个特点:只读、共享)

全局区:存放全局变量、静态变量以及常量的区域;(该区域的数据在程序结束后由操作系统释放)

栈区:编译器自动分配释放,存放函数的参数值、局部变量等;(不要返回局部变量的地址,因为栈区开辟的数据由编译器自动释放)

堆区:由程序员分配释放,若程序员不释放,程序结束后由操作系统回收;(在 C++ 中要利用关键字 new 来开辟内存,用关键字 delete释放内存,相当于C语言中的 mallocfree

代码区、全局区程序运行前生成,栈区、堆区程序运行后生成;

内存四区的意义:不同区域存放不同数据,赋予不同的生命周期,给我们更大的灵活编程;


常量:

1.字符串常量

2.const 修饰的变量:I.const 修饰的全局变量;(全局常量)

II.const 修饰的局部变量;(局部常量)

全局区:

1.全局变量、静态变量

2.常量区:I.字符串常量;

II.const 修饰的全局变量(全局常量);


全局区和栈区的区分:

全局区栈区
全局变量、静态变量局部变量
…(中间隔了一段位置,意思即是常量虽然也在全局区里面,但真正的位置和全局变量、静态变量之间还隔了一小段)函数形参
字符串常量、全局常量局部常量

总结:名字中带有“局部”的字眼,无论它是常量还是变量,都存放在栈区中, 其他的按照上面所说的存在相应的内存区中;


C++还在学习中O(∩_∩)O,之后还会更新笔记!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值