C++ 限定符Const和指针

指向常量的指针

指向常量的指针不能用于其所指对象的值。若想存放常量对象的地址,只能使用指向常量的指针。

1
2
3
4
const int a =  3;	//a是个常量,其值不能改变
int *b = &a; //错误:b是个普通指针
const int *c = &a; //正确
*c = 8; //错误:c不能给a赋值

允许一个指向常量的指针指向一个非常量,但不能通过该指针修改这个非常量的值(但该非常量可以通过其他途径修改)。

1
2
int d = 0;	//一个整型变量
c = &d; //正确,但不能通过指针c修改d的值

const指针

常量指针必须初始化,而且一旦初始化完成其值(也就是放在指针的那个地址)就不能改变了。把*放在const前说明不变的是指针的值而不是所指的那个值。

1
2
3
4
5
6
7
8
9
int a = 0;
int b = 1;
const int *c = &a;
int *const d = &a;


c = &b; //正确:但不能通过c改变b的值
*d = 5; //正确:可以通过d改变a的值
d = &b; //错误:d是一个常量指针,其本身的值不能改变

顶层const与底层const

基本概念

指针本身是不是常量指针所指对象是不是常量是两个相互独立的问题。
用名词 顶层 const 表示本身是个常量。
用名词 底层 const 表示所指对象是个常量。

  • 一般的,顶层const可以表示任意的对象。底层cosnt则与指针和引用等复合类型的基本类型有关。
  • 特殊的,指针可以同时是顶层const底层const;声明引用的const都是底层cosnt
1
2
3
4
int a = 0;
int *const p1 = &i; //顶层const
const int b = 42; //顶层const
const int *p2 = &b; //底层const

拷贝操作

  • 顶层const在进行拷贝操作时不受什么影响
    1
    2
    const int a = 0;
    int b = a; //正确:二者类型相同且顶层const不受影响
  • 底层const的限制不能忽视!拷入和烤出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说非常量能转换成常量,反之则不行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const int a = 0;
    const int *const p = &a; //具有顶层和底层const的指针p,靠右边的是顶层,靠左边的是底层
    const int &b = a; //声明引用的const都是底层const
    int b = a; //正确:a包含顶层const,无影响


    int *p1 = p; //错误:p包含底层const,p1没有
    const int *p2 = p; //正确:二者都包含底层const,p的顶层const无影响

    int i = 1;
    p2 = &i; //正确:int*能转换成const int*

C/C++在Win32控制台播放Bad Apple

前言

效果展示

BadApple-Win32

###提示###
这里首先你需要准备一些文件,将一个Bad Apple的视频分别转换成txtmp3格式(mp3用来作为背景音乐)
我将txt文件放到exe文件目录下的子目录files里了
转换方法可以用Adobe,这里不做详细介绍,你可以下载我已经准备好的文件,在文章末尾会给出连接

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include <mmsystem.h>

#pragma comment (lib,"Winmm.lib") //加载windows播放音乐的库

#define MAX_ROW 66
#define MAX_COL 150
#define MAX_FRAME 13148

char map[MAX_FRAME][MAX_ROW][MAX_COL+1];

void init(){
SetConsoleTitle("BadApple"); //控制台标题

system("mode con cols=151 lines=68");

HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info = { 1,0 };
SetConsoleCursorInfo(hout, &info);

}

//读取文件
void readData() {
FILE* fp; //文件指针
char fileName[128]; //文件名

for (int i = 0; i < MAX_FRAME; i++) {
//每次读取一个文件
int row = 0;
sprintf(fileName, "files/ASCII-badApple60fps%05d.txt", i); //生成一个文件名
fp = fopen(fileName, "r");
if (fp == NULL) {
exit(1);
}

//当文件读完时结束循环
while (!feof(fp)) {
fgets(map[i][row],200,fp);
map[i][row][MAX_COL] = '\0'; //取消每行最后的回车符
row++;
}
fclose(fp);
}
}

//播放动画函数
void play() {

system("cls"); //清屏
for (int i = 0; i < MAX_FRAME; i++) {
for (int j = 0; j < MAX_ROW; j++) {
//如果用printf()的话由于之前我们取消了换行符,所以要在此处加上
puts(map[i][j]); //不断打印到每一行
}
Sleep(2); //休眠2毫秒

//把光标引到最前方
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE); //控制台

COORD loc; //引入结构体,并定义xy初始坐标
loc.X = 0;
loc.Y = 0;
SetConsoleCursorPosition(houtput, loc);
}


}

int main(void) {
init(); //初始化

//将文本文件加载到计算机内存
readData();


//开始播放
while (1) {
//播放背景音乐
mciSendString("play bg.mp3", 0, 0, 0);
play();
}

return 0;
}

文件

百度网盘链接:https://pan.baidu.com/s/1i8UEQsw5UPoLX7S41Xk9Hw
提取码:8848

C++实现服务器与客户端网络通讯

说明

  • 本程序并没有区分服务端与客户端,只是调用函数不同
  • 基于socket网络编程
  • 第一次写,代码格式不怎么规范,请谅解
  • 基于Linux,Win版本目前没写
  • 接下来准备基于本程序搞一个更大的项目

说明:
ClientInfor(); 为客户端使用
ServerInfor(); 为服务端使用
二者不能同时用,因为用了相同的buf变量
通过adjust变量作为函数参数来切换收发消息

原理

此处暂时省略,过段时间会补上

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<arpa/inet.h>
#include <iostream>


const int MAXLINE = 4096;
const int PORT = 2726;


int sockfd, connfd; //sock句柄和连接句柄
struct sockaddr_in SerAddr;
char buf[MAXLINE];
int size;




using namespace std;

int ServerSockConn()
{
//检查连接并报错
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
cout << " Socket connect failed:" << errno << endl;
return 0;
}

//储存相关信息,如IP等
memset(&SerAddr, 0, sizeof(SerAddr));
SerAddr.sin_family = AF_INET;
SerAddr.sin_port = htons(PORT);
SerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

//检测绑定并报错
if (bind(sockfd, (struct sockaddr*)&SerAddr, sizeof(SerAddr)) == -1)
{
cout << "Bind socket failed: " << errno << endl;
return 0;
}

//检测监听并报错
if( listen(sockfd, 10) == -1)
{
cout << "Listen socket failed: " << errno << endl;
return 0;
}
}

void GetInfor()
{
recv(connfd, buf, MAXLINE, 0);
cout << buf << endl;
close(connfd);
}

void SendInfor()
{
send(connfd, "Send", 15, 0);
}

//若为真则接收消息,若为假则发送消息
void ServerInfor(bool adj)
{
ServerSockConn();
while(1)
{
if ( (connfd = accept(sockfd, (struct sockaddr*)NULL,NULL)) == -1) //同意请求
{
cout << "Accept socket failed: " << errno << endl;
continue;
}

if (adj == true)
{
GetInfor();
}

else
{
SendInfor();
}
}
close(sockfd);
}



//客户端

int socketfd,n;
char recvline[MAXLINE], sendline[MAXLINE];
struct sockaddr_in CliAddr;


//真收,假发

int ClientInfor(bool adj)
{
socketfd = socket(AF_INET,SOCK_STREAM,0); //建立连接
if (socketfd == -1)
{
cout << "Socket failed:" << errno << endl;
}


CliAddr.sin_family=AF_INET;
CliAddr.sin_port=htons(PORT);
CliAddr.sin_addr.s_addr=inet_addr(""); //引号内为服务器公网IP
bzero(&(CliAddr.sin_zero),8);
if ( connect(socketfd,(struct sockaddr*)&CliAddr,sizeof(struct sockaddr)) == -1 ){
cout << "Connect failed:" << errno << endl;
}
else
{
if (adj == true)
{
recv(socketfd,buf,MAXLINE,0);
cout << buf << endl;
}
else
{
cout << "Please input" << endl;
send(socketfd,"conn",15,0);
close(socketfd);
}
}

}



int main()
{

//修改adjust变量来控制消息收发,为真则默认收,为假则发送
bool adjust = false;
/*
说明:
ClientInfor(); 为客户端使用
ServerInfor(); 为服务端使用
二者不能同时用,因为用了相同的buf变量
通过adjust变量作为函数参数来切换收发
*/


return 0;

}


C++最小二乘计算回归方程

介绍

用来理解一下数学思路和练习一下代码。即兴而写的,所以没写注释。
最小二乘法

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
// #include "Windows.h"

double sum_square_x = 0;
double sum_x = 0;
double sum_y = 0;
double sum_xy = 0;
int n = 0;
double ave_x = 0;
double ave_y = 0;
double b_ba = 0;
double a_ba = 0;

using namespace std;

void InputAndSum()
{
cout << "请输入n的值" << endl;
cin >> n;
cout << " " << endl;
double data_x = 0;
double data_y = 0;
int i = 1;
while (i <= n)
{
cout << "请输入第" << i << "个数据的x值" << endl;
cin >> data_x;
cout << " " << endl;
cout << "请输入第" << i << "个数据的y值" << endl;
cin >> data_y;
cout << " " << endl;

sum_x += data_x;
sum_y += data_y;
sum_xy += (data_x * data_y);
sum_square_x += (data_x * data_x);

i++;
}

}

double Average(double a)
{
double ave = a / n;
return ave;
}

double B_ba(double calc1,double calc2)
{
double square_ave_x = calc1 * calc1;
double calc3;
calc3 = (sum_xy - n * calc1 * calc2) / (sum_square_x - n * square_ave_x);
return calc3;
}

void A_ba()
{
a_ba = ave_y - b_ba * ave_x;
}

int main()
{
InputAndSum();
ave_x = Average(sum_x);
ave_y = Average(sum_y);
b_ba = B_ba(ave_x,ave_y);
A_ba();
cout << "---------------------------------" << endl;
cout << "---------------------------------" << endl;
cout << "n的值为: " << n << endl;
cout << "各x的和为: " << sum_x << endl;
cout << "各y的和为: " << sum_y << endl;
cout << "各个xy乘积的求和为: " << sum_xy << endl;
cout << "各个x平方的求和为: " << sum_xy << endl;
cout << "x的均值为: " << ave_x << endl;
cout << "y的均值为: " << ave_y << endl;
cout << "a(ba)为: " << a_ba << endl;
cout << "b(ba)为: " << b_ba << endl;
cout << "样本点中心为:(" << ave_x << "," << ave_y << ")" << endl;
cout << "回归直线方程为 y = " << b_ba << "x + " << "(" << a_ba << ")" << endl;
cout << "---------------------------------" << endl;
cout << "---------------------------------" << endl;
//system("pause");

}

C语言运算符

最高级

1
2
3
4
() 圆括号
[] 下标运算符号
-> 指向结构体成员运算符
. 结构体成员运算符

第二级

1
2
3
4
5
6
7
8
9
! 逻辑非运算符
~ 按位取反运算符
++ 自增运算符
-- 自减运算符
- 负号运算符
(type) 类型转换运算符
* 指针运算符
& 取址运算符
sizeof 长度运算符

第三级

1
2
3
4
5
*乘法运算符
/除法运算符
%取余运算符
+加法运算符
-减法运算符

第四级

1
2
<< 左移运算符 00001111变成00011110
>> 右移运算符 00001111变成00000111

第五级

1
2
3
< <= > >= 关系运算符
!= 不等运算符
== 等于运算符

第六级

1
2
3
& 按位运算符
^ 按位异或运算符
| 按位或运算符

第七级

1
2
3
&&   (表达式1)&&(表达式2) 表达式1不成立,不考虑表达式2,直接返回0
|| (表达式1)||(表达式2) 表达式1成立,不考虑表达式2,直接返回1
&&优先级大与||

第八级

1
2
3
4
? : 
例: z=x>y?x:y
如果x>y,把x赋值给z
如果x<=y,把y赋值给z

第九级

1
2
3
4
5
6
=
+=
-+
*=
/=
%=

最低级

1
,

C++ 输出斐波那契数列

代码

先贴代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
using namespace std;
int main(){
int n = 1;
double n_m = 93;
cout << endl;
while(1){
int n = 1;
long long int a=1;
long long int b=1;
cout << "Please input the max value of n." << endl;
cin >> n_m;
int n_max = static_cast<int> (n_m);
if (n_max < 1){
cout << "The max value of n is error." << endl;
}
if (n_max > 92){ //因为斐波那契数列发散很快,所以给n一个上限,防止数列数值溢出
cout << "The value is too large." << endl;
}
else{
while(n <= n_max){
if (n == 1){
cout << a << endl;
n++;
}
if ( n== 2){
cout << b << endl;
n++;
}
else{
a = a+b;
cout << a << endl;
n++;
b = a+b;
cout << b << endl;
n++;
}
}
}
}
}
  • 复制

相关知识

斐波那契数列递推关系F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
通项公式

为便于理解,本文章方法是根据递推关系来写的程序
相关数学知识请参考:百度百科