c++ - 是否可能存在不会导致程序崩溃的内存问题?

标签 c++

我写了一个文本密码程序。它似乎适用于几个字符长的文本字符串,但不适用于较长的文本字符串。它通过从文本文件中读取来获取输入文本。在较长的文本字符串上,它仍然可以运行而不会崩溃,但似乎无法正常工作。

下面我隔离了执行该文本加扰的代码。如果它有用,我在运行 Ubuntu 19.04 的虚拟机中运行它。运行代码时,在出现提示时输入 auto。我删除了其余代码,因此不会太长。

#include <iostream>
#include <string>
#include <sstream>
#include <random>
#include <cmath>
#include <cctype>
#include <chrono>
#include <fstream>
#include <new>


bool run_cypher(char (&a)[27],char (&b)[27],char (&c)[11],char (&aa)[27],char (&bb)[27],char (&cc)[11]) {
//lowercase cypher, uppercase cypher, number cypher, lowercase original sequence, uppercase original sequence, number original sequence
std::ifstream out_buffer("text.txt",std::ios::in);
std::ofstream file_buffer("text_out.txt",std::ios::out);
//out_buffer.open();
out_buffer.seekg(0,out_buffer.end);
std::cout << "size of text: " << out_buffer.tellg() << std::endl;//debug
const int size = out_buffer.tellg();
std::cout << "size: " << size << std::endl;//debug
out_buffer.seekg(0,out_buffer.beg);
char *out_array = new char[size + 1];
std::cout << "size of out array: " << sizeof(out_array) << std::endl;//debug
    for (int u = 0;u <= size;u = u + 1) {
    out_array[u] = 0;
    }
out_buffer.read(out_array,size);
out_buffer.close();
char original[size + 1];//debug
    for (int bn = 0;bn <= size;bn = bn + 1) {//debug
    original[bn] = out_array[bn];//debug
    }//debug
    for (int y = 0;y <= size - 1;y = y + 1) {
    std::cout << "- - - - - - - -" << std::endl;
    std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
    int match;
    int case_n; //0 = lowercase, 1 = uppercase
        if (isalpha(out_array[y])) {
            if (islower(out_array[y])) {
            //std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
            //int match;
                for (int ab = 0;ab <= size - 1;ab = ab + 1) {
                    if (out_array[y] == aa[ab]) {
                    match = ab;
                    case_n = 0;
                    std::cout << "matched letter: " << aa[match] << std::endl;//debug
                    std::cout << "letter index: " << match << std::endl;//debug
                    std::cout << "case_n: " << case_n << std::endl;//debug
                    }
                }
            }
            if (isupper(out_array[y])) {
                for (int cv = 0;cv <= size - 1;cv = cv + 1) {
                    if (out_array[y] == bb[cv]) {
                    case_n = 1;
                    match = cv;
                    std::cout << "matched letter: " << bb[match] << std::endl;//debug
                    std::cout << "letter index: " << match << std::endl;//debug
                    std::cout << "case_n: " << case_n << std::endl;//debug
                    }
                }
            }
            if (case_n == 0) {
            out_array[y] = a[match];
            std::cout << "replacement letter: " << a[match] << " | new character: " << out_array[y] << std::endl;//debug
            }
            if (case_n == 1) {
            std::cout << "replacement letter: " << b[match] << " | new character: " << out_array[y] << std::endl;//debug
            out_array[y] = b[match];
            }

        }
        if (isdigit(out_array[y])) {
            for (int o = 0;o <= size - 1;o = o + 1) {
                if (out_array[y] == cc[o]) {
                match = o;
                std::cout << "matched letter: " << cc[match] << std::endl;//debug
                std::cout << "letter index: " << match << std::endl;//debug
                }
            }
        out_array[y] = c[match];
        std::cout << "replacement number: " << c[match] << " | new character: " << out_array[y] << std::endl;//debug
        }
    std::cout << "- - - - - - - -" << std::endl;
    }
std::cout << "original text: " << "\n" << original << "\n" << std::endl;    
std::cout << "encrypted text: " << "\n" << out_array << std::endl;
delete[] out_array;
return 0;
}

int main() {
const int alpha_size = 27;
const int num_size = 11;
char l_a_set[] = "abcdefghijklmnopqrstuvwxyz";
char cap_a_set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char n_a_set[] = "0123456789";
std::cout << "sizeof alpha_set: " << std::endl;//debug
char lower[alpha_size] = "mnbvcxzasdfghjklpoiuytrewq";
char upper[alpha_size] = "POIUYTREWQASDFGHJKLMNBVCXZ";
char num[num_size] = "9876543210"; 
int p_run; //control variable. 1 == running, 0 == not running
int b[alpha_size]; //array with values expressed as index numbers
std::string mode;
int m_set = 1;
    while (m_set == 1) {
    std::cout << "Enter 'auto' for automatic cypher generation." << std::endl;
    std::cout << "Enter 'manual' to manually enter in a cypher. " << std::endl;
    std::cin >> mode;
    std::cin.ignore(1);
    std::cin.clear();
        if (mode == "auto") {
        p_run = 2;
        m_set = 0;
        }
        if (mode == "manual") {
        p_run = 3;
        m_set = 0;
        }
    }
    if (p_run == 2) { //automatic mode
    std::cout <<"lower cypher: " << lower << "\n" << "upper cypher: " << upper << "\n" << "number cypher: " << num << std::endl;//debug
    run_cypher(lower,upper,num,l_a_set,cap_a_set,n_a_set);
    return 0;//debug
    }
    while (p_run == 3) {//manual mode
    return 0;//debug    
    }
return 0;
}

例如,使用包含“mnbvcxzasdfghjklpoiuytrewq”的数组作为小写字母的密码,如果输入是“abcd”,我得到“mnbv” 。这是对的。

如果输入是“a long word”,我得到“m gggz zzzv”作为输出,而它应该是“m gkjz rkov”。有点正确但仍然是错误的。如果我使用“这是一个非常非常长的句子,将导致程序失败”作为输入,我得到“uas”作为输出,这是完全错误的。该程序仍在运行,但无法按预期运行。如您所见,它确实有效,但对任何远程长文本字符串无效。这是内存问题还是我在某处犯了可怕的错误?

最佳答案

对于您的特定代码,您应该通过诸如 valgrind 之类的内存检查工具运行它,或者使用 address sanitizer. 进行编译。

以下是一些很可能不会使您的程序崩溃的内存问题示例:

  1. 忘记删除在程序中只分配一次的小对象。如果内存泄漏没有使程序耗尽内存,那么它可能会在数十年内未被发现。
  2. 从分配的未初始化内存中读取。如果系统在第一次写入时延迟分配对象,可能仍会崩溃。
  3. 在大小为 sizeof(obj) % 8 != 0 的堆上对象之后稍稍写出边界。之所以如此,是因为堆分配通常以 8 或 16 的倍数完成。您可以阅读相关信息 at answers of this SO question .
  4. 取消引用 nullptr 在某些系统上不会崩溃。例如,AIX 过去常常在地址 0x0 处和附近放置零。较新的 AIX 可能仍会这样做。

    在许多没有内存管理的系统上,地址零要么是常规内存地址,要么是内存映射寄存器。可以在不崩溃的情况下访问此内存。

    在我尝试过的任何系统(基于 POSIX)上,都可以通过内存映射在地址零处分配有效内存。这样做甚至可以通过 nullptr 进行写入而不会崩溃。

这只是部分列表。

注意:这些内存问题是未定义的行为。这意味着即使程序没有在 Debug模式下崩溃,编译器也可能在优化期间假设错误的事情。如果编译器假定了错误的事情,它可能会创建一个优化后的代码,但在优化后会崩溃。

例如,大多数编译器会优化这个:

int a = *p; // implies that p != nullptr
if (p) 
   boom(p);

进入这个:

int a = *p;
boom(p);

如果系统允许取消引用 nullptr,那么此代码可能会在优化后崩溃。它不会因为取消引用而崩溃,而是因为优化做了一些程序员没有预见到的事情。

关于c++ - 是否可能存在不会导致程序崩溃的内存问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55913562/

相关文章:

c++ - 弧形二维碰撞检测

c++ - Cpp/C++ 唯一的指针,用于访问该类的对象函数

c++ - 如何将图表读入 Boost 图表库中的邻接矩阵?

c++ - 由 4 个十六进制字符组成的数字

c++ - Windows 2000 的 GetProcessID 的替代方法

c++ - 使用 fs::recursive_directory_iterator() 和 fs::directory_iterator() 的通用方法

c++ - 使用递归 C++ 最大化函数

c++ - 结构 vector 工程

c++ - vector 类错误

c++ - u8、u 和 U 字符串文字背后的推理