C++学习路线(十九)

函数返回值指针

cpp 复制代码
#include <iostream>
using namespace std;

int* add(int x, int y) {
	// 定义一个指针
	int* sum = NULL;
	// 让指针指向堆内存 也就是sum的值是堆的地址
	sum = new int;
	*sum = x + y;
	// 返回指针 以拷贝的方式返回
	// 也就是 外部的sum指针指向的地址和堆内存的地址是一样的
	return sum;
}
int* add1(int x, int y) {
	int sum = x + y;
	//将这个局部变量的地址返回
	return &sum;
}
//因为 上面的sum的存储期是 auto 所以 它会在函数执行完毕后自动释放内存
//也就是sum这个地址里面存的是垃圾值 因为是在栈上分配的

// 因为是静态变量 所以只会在第一次调用的时候分配内存 分配到静态区 不会被清理
int* add2(int x, int y) {
	static int num = 0;
	num = x + y;
	return &num;
}
int main() {
	int a = 3, b = 5;
	int* sum = NULL;
	sum = add2(a, b);
	cout << "Sum is: " << *sum << endl;
	return 0;
}

常见错误总结

1.申请的内存多次释放

2.内存泄漏

3.释放的内存不是申请时的地址

4.释放空指针

5.释放一个内存块,但继续引用其中的内容

6.越界访问

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
	//1.多次释放内存
	int* p = new int[10];
	delete[] p;
	//--------
	//2.内存泄漏
	do {
		int* p = new int[1000000000];
	} while (1 == 1);
	//3.释放的时候不是申请时候的地址
	int* p2 = new int[10];
	for (int i = 0; i < 10; i++) {
		cout << *(p2++) << endl;
	}
	delete[] p2; // 这个时候的p2 已经不是申请时候的地址了,所以会导致内存泄漏
	//4,释放空指针
	//我们构造一种情况
	int* pfile = NULL;
	if (1) { // 加入能打开文件
		pfile = new int[2048];
	}
	// 这里的if语句中,有可能发生异常,导致pfile为NULL,此时应该释放pfile
	delete[] pfile; // 释放空指针

	//5.释放一个内存块 但在引用里面的内容
	int* p4 = new int[10];
	delete[] p4; // 释放p4
	p4[0] = 1; // 引用里面的内容

	//6.越界访问
	int* p5 = new int[10];
	for (int i = 0; i <= 10; i++)
		p5++; // 越界访问

}

具体开发需求

1.问题描述:
使用数据文件中的一组地震检波器测量值确定可能的地震事件的位置

2、输入输出描述:

程序的输入是名为 seismic.dat的数据文件和用于计算短时间能量和长时间能量的取样值的数目输出是给出关于潜在的地震事件次数的报告。

seismic.dat 的结构是这样的,第一行包含两个值: 地震检波器能量值的数目和时间间隔,从第二行开始就是能量值的数据,以空格分开

短时间窗口和长时间窗口的值可以由键盘读入

判定地震事件给定的阀值是 1.5

算法设计

1)读取文件头并分配内存;

2)从数据文件读取地震数据,从键盘读取计算能量的短时间和长时间窗口测量值的数目;

3)计算各个时间点上的短时间窗口和长时间窗口的能量值,打印出可能的地震事件时间。在这里,因为会涉及到频紧调用短窗口和长窗口量位我们可以将计算能量值设计为单独的一个函数

cpp 复制代码
#include <iostream>
#include <fstream>
#include <assert.h>
using namespace std;
#define MAXN 1024
double threshold = 1.5;
int dot[MAXN] = { 0 };

double calValue(int left, int right) {
	double sum = 0;
	for(int i  =left ; i <= right ; i ++ )
		sum += pow(dot[i] , 2);
	return sum / (right - left + 1);
}


int main() {
	string path = "E:\\c++file\\地震.txt";
	ifstream file(path);
	if (!file.is_open()) {
		cout << "文件打开失败!" << endl;
		exit(1);
	}
	int dotLen;
	double betweenLen;
	file >> dotLen >> betweenLen;
	
	for (int i = 0; i < dotLen; i++) {
		if(file.eof()) break;
		file >> dot[i];
		if (file.fail()) {
			cout << "数据格式错误!" << endl;
			exit(1);
		}
	}
	int longLen, shortLen;
	cout << "请输入长波峰长度:";
	cin >> longLen;
	cout << "请输入短波峰长度:";
	cin >> shortLen;
	assert(longLen > 0 && shortLen > 0);
	assert(longLen > shortLen && longLen < dotLen && shortLen < dotLen);
	for (int index = longLen - 1; index < dotLen; index++ ) {
		double longValue = calValue(index - longLen + 1, index);
		double shortValue = calValue(index - shortLen + 1, index);
		double diff = shortValue / longValue;
		if (diff > threshold) {
			cout << betweenLen * index << endl;
		}
	}
	file.close();
	return 0;
}

编程思维修炼

在一次竟赛中,A、B、C、D、E等五人经过激烈的角逐,最终取得了各自的名次,他们的一个好朋友很遗憾没有观看到比赛,在比赛结束后这个朋友询问他们之间的名次是得知:C不是第一名,D比E低二个名次,而E不是第二名,A即不是第一名,也不是最后一名,B比C低一个名次。编写程序,计算这五个人各自的名次并输出。

列出已知条件

  1. C 不是第一名。
  2. D 比 E 低两个名次。
  3. A 既不是第一名,也不是最后一名。
  4. B 比 C 低一个名次。
    步骤 1: 分析条件 1 和 3
  • C 不是第一名,因此 C 只能是第 2、3、4 或 5 名。

  • A 既不是第一名也不是最后一名,所以 A 只能是第 2、3 或 4 名。

  • C=2,3,4,5

  • A = 2,3,4
    步骤 2: 分析条件 2 和 4

  • D 比 E 低两个名次。如果 D 是第 3 名,那么 E 必须是第 1 名;如果 D 是第 4 名,E 就是第 2 名;如果 D 是第 5 名,E 就是第 3 名。

  • B 比 C 低一个名次。这意味着如果 C 是第 2 名,B 就是第 3 名;如果 C 是第 3 名,B 就是第 4 名;如果 C 是第 4 名,B 就是第 5 名。

  • E,D 1,3 2,4 3,5

  • C,B 1,2 2,3 3,4 4,5

我的想法 遍历 c , 可以确定b 然后我们遍历a和 e 可以确定d 然后看看有没有符合的

cpp 复制代码
#include <iostream>
#include <map>
using namespace std;

int main() {
	// 我们遍历C 2-5
	for (int c = 2; c <= 4; c++) {
		int b = c + 1;
		for (int a = 2; a <= 4; a++) {
			for (int e = 1; e <= 3; e++) {
				if (e == 2) continue;
				int d = e + 2;
				map<int, int> mp;
				mp[a] = 1;
				mp[b] = 1;
				mp[c] = 1;
				mp[d] = 1;
				mp[e] = 1;
				if(mp.size() == 5)
					cout << "a:" << a << " b:" << b << " c:" << c << " d:" << d << " e:" << e << endl;
			}
		}
	}
	return 0;
}

内存泄漏工具

使用 c++库来检测内存泄露

第一步 包含头文件

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

第二步 接管new操作符

#ifdef _DEBUG

#ifndef DBG_NEW

#define DBG_NEW new ( _NORMAL_BLOCK, FILE, LINE )

#define new DBG_NEW

#endif

#endif

第三步 在代码结束输出泄露的信息

cpp 复制代码
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <iostream>
#include <Windows.h>
using namespace std;

#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK, __FILE__, __LINE__ )
#define new DBG_NEW
#endif
#endif 

void func() {
	int* p = new int[128];
}
int main() {

	for (int i = 0; i < 5; i++) {
		func();
		Sleep(100);
	}

	_CrtDumpMemoryLeaks();
}

点击本地调试 不要点击release

内存泄漏工具

Windows : Purify,BoundsCheaker 、Deleaker、VisualLeak Detector(VLD )

Linux:Valgrind memcheck

项目练习

1.编写一个程序,链接两个字符串字面常量,将结果保存在一个动态分配的 char数组中。重写这个程序,连接两个标准string 对象。

cpp 复制代码
#include <iostream>
using namespace std;

char* linkTwoString(const char* str1, const char* str2) {
	char* result = new char[strlen(str1) + strlen(str2) + 1];
	strcpy(result, str1);
	strcat(result, str2);
	return result;
}

char* linkTwoString_2(const string& str1, const string& str2) {
	char* result = new char[str1.length() + str2.length() + 1];
	strcpy(result, str1.c_str());
	strcat(result, str2.c_str());
	return result;
}

int main() {
	char* result = linkTwoString("Hello", "World");
	cout << result << endl;
	delete[] result;
	char* result2 = linkTwoString_2("Hello", "World");
	cout << result2 << endl;
	return 0;
}

2.编写一个程序,使用 cin,从标准输入输入3段文字,保存到一段动态分配的内存中,每一段文字输入后,必须要即时保存到动态内存中。

cpp 复制代码
#include <iostream>
#include <cstring> // For strcpy, strcat, strlen
#include <cstdlib> // For malloc, free
#include <string>

int main() {
    // 初始分配一小块内存
    char* dynamicMemory = (char*)malloc(1);
    if (dynamicMemory == nullptr) {
        std::cerr << "内存分配失败!" << std::endl;
        return 1;
    }
    dynamicMemory[0] = '\0'; // 初始化为一个空字符串
    // 定义每段文本的最大长度
    const int maxLength = 100;
    for (int i = 1; i <= 3; ++i) {
        std::cout << "请输入第 " << i << " 段文字(最多 " << maxLength - 1 << " 个字符): ";
        // 使用std::string临时存储输入
        std::string inputString;
        std::getline(std::cin, inputString);

        // 计算新的内存大小
        size_t newLength = strlen(dynamicMemory) + inputString.size() + 1; // +1 for null terminator
        char* temp = (char*)realloc(dynamicMemory, newLength * sizeof(char));
        if (temp == nullptr) {
            std::cerr << "内存分配失败!" << std::endl;
            return 1;
        }
        dynamicMemory = temp;
        // 将输入的字符串复制到动态内存中
        strcat(dynamicMemory, inputString.c_str());

    }
    // 输出结果
    std::cout << "您输入的所有文本:" << std::endl;
    std::cout << dynamicMemory << std::endl;
    // 释放动态分配的内存
    free(dynamicMemory);
    dynamicMemory = nullptr;
    return 0;
}

3.下列程序的功能是:首先,根据输入的二维数组的行数和列数,动态地为该数组分配存储空间;

其次,向二维数组中输入数据;最后输出该数组中的所有元素。请完善下面的程序。

cpp 复制代码
#include <iostream>
using namespace std;
int main() {
	int rows, cols;
	printf("Enter the number of rows and columns: ");
	cin >> rows >> cols;
	int** arrays = (int**)malloc(rows * sizeof(int*));
	if (!arrays) {
		printf("Memory allocation failed.\n");
		return 1;
	}
	//为每一行分配内存
	for (int i = 0; i < rows; i++) {
		arrays[i] = (int*)malloc(cols * sizeof(int));
		if (!arrays[i]) {
			printf("Memory allocation failed.\n");
			return 1;
		}
	}
	printf("Enter the elements of the matrix:\n");
	for(int i = 0 ; i < rows ; i ++ )
		for(int j = 0 ; j < cols ; j ++ )
			cin >> arrays[i][j];
	printf("The matrix is:\n");
	for(int i = 0 ; i < rows ; i ++ ) {
		for(int j = 0 ; j < cols ; j ++ )
			printf("%d ", arrays[i][j]);
		printf("\n");
	}
	//释放内存
	for (int i = 0; i < rows; i++) {
		free(arrays[i]);
	}
	free(arrays);
	return 0;
}

这个是使用指针

cpp 复制代码
#include <iostream>
using namespace std;
int main() {
	int rows, cols;
	printf("Enter the number of rows and columns: ");
	cin >> rows >> cols;
	int** arrays = (int**)malloc(rows * sizeof(int*));
	if (!arrays) {
		printf("Memory allocation failed.\n");
		return 1;
	}
	//为每一行分配内存
	for (int i = 0; i < rows; i++) {
		*(arrays + i) = (int*)malloc(cols * sizeof(int));
		if (!(arrays + i)) {
			printf("Memory allocation failed.\n");
			return 1;
		}
	}
	printf("Enter the elements of the matrix:\n");
	for (int i = 0; i < rows; i++)
		for (int j = 0; j < cols; j++)
			cin >> *(*(arrays + i) + j);
	printf("The matrix is:\n");
	for(int i = 0 ; i < rows ; i ++ ) {
		for(int j = 0 ; j < cols ; j ++ )
			printf("%d ", *(*(arrays + i) + j));
		printf("\n");
	}
	//释放内存
	for (int i = 0; i < rows; i++) {
		free(arrays[i]);
	}
	free(arrays);
	return 0;
}
相关推荐
机器视觉知识推荐、就业指导1 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
朝九晚五ฺ1 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
Swift社区2 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman2 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
猫爪笔记3 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
IT 青年3 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Yang.993 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王3 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_3 小时前
C++自己写类 和 运算符重载函数
c++