【问题标题】:Changing sprintf to an array of characters C++将 sprintf 更改为字符数组 C++
【发布时间】:2026-01-08 08:40:01
【问题描述】:

我有一个二维单词数组。

void main() {
    const int rowsCount = 2;
    const int colsCount = 5;

    char*** szData = new char** [rowsCount];

    //Allocate memory for each row
    for (int i = 0; i < rowsCount; i++)
    {
        szData[i] = new char* [colsCount]; //how many words in every row
        for (int j = 0; j < colsCount; j++)
        {
            szData[i][j] = new char[15]; //maximum symbols in a word
        }
    }

    //Assign some data
    for (int i = 0; i < rowsCount; i++)
    {
        char s[] = "Williams";
        szData[i][0] = s;

        sprintf(szData[i][0], "Williams%d", 0);
        sprintf(szData[i][1], "J.%d", 0);
        sprintf(szData[i][2], "#3%d", 0);
        sprintf(szData[i][3], "100%d", 0);
        sprintf(szData[i][4], "01.13%d", 0);
    }
...
}

在分配数据时,我试图改变它

sprintf(szData[i][0], "Williams%d");

到这里

char s[] = "Williams";
szData[i][0] = s;

为什么我不断收到我的项目“已触发断点”的消息?

有没有使用字符数组来替代sprintf?不能使用string(本任务条件之一)

另外,没那么必要,但如果我在此处删除最后的 0

sprintf(szData[i][0], "Williams%d", 0);
sprintf(szData[i][1], "J.%d", 0);
sprintf(szData[i][2], "#3%d", 0);
sprintf(szData[i][3], "100%d", 0);
sprintf(szData[i][4], "01.13%d", 0);

每个单词后面都会出现一些数字。例如:Williams3937516。这是为什么呢?

完整代码:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <conio.h> 

using namespace std;

void main() {
    const int rowsCount = 2;
    const int colsCount = 5;

    char*** szData = new char** [rowsCount];

    //Allocate memory for each row
    for (int i = 0; i < rowsCount; i++)
    {
        szData[i] = new char* [colsCount]; //how many words in every row
        for (int j = 0; j < colsCount; j++)
        {
            szData[i][j] = new char[15]; //maximum symbols in a word
        }
    }

    //Assign some data
    for (int i = 0; i < rowsCount; i++)
    {
        char s[] = "Williams";
        szData[i][0] = s;

        sprintf(szData[i][0], "Williams%d");
        sprintf(szData[i][1], "J.%d", 0);
        sprintf(szData[i][2], "#3%d", 0);
        sprintf(szData[i][3], "100%d", 0);
        sprintf(szData[i][4], "01.13%d", 0);
    }

    //print all the elements
    for (int i = 0; i < rowsCount; i++)
    {

        for (int j = 0; j < colsCount; j++)
        {
            cout << szData[i][j] << " ";
        }
        cout << endl;

    }

    //free memory here
    for (int i = 0; i < rowsCount; i++)
    {
        for (int j = 0; j < colsCount; j++)
        {
            delete[] szData[i][j];
        }
    }

    for (int i = 0; i < rowsCount; i++)
    {
        delete[] szData[i];
    }

    delete[] szData;
}

【问题讨论】:

  • 如果您的意图是编写 C++ 代码,您希望使用 C++ 容器,如 vectors,为您正确、准确地管理所有内存分配。上面看起来像容易出错的 C 代码而不是 C++。现代 C++ 很少需要使用newdelete。显示的代码中存在某种关于内存分配的错误,但与其浪费时间试图弄清楚它是什么,一个更简单的解决方案是使这种错误在逻辑上不可能发生。废弃所有内容,并使用现代 C++ 容器和基于迭代器的代码从头开始重写。
  • 我正在大学学习,但还不能使用vector 完成,很遗憾(任务的另一个条件)

标签: c++ arrays char


【解决方案1】:

如果追溯这个指针的赋值:

char s[] = "Williams";

你会发现你正在尝试释放它的内存:

delete[] szData[i][j];

但是,您不能这样做 - 字符串 "Williams" 从未使用 new 分配,因此无法使用 delete 释放它。事实上,它是静态分配的,在你的二进制文件中。所以堆报错,这就是断点的原因。

如果您要使用delete szData 中的所有内容,您需要确保所有内容都使用new 在堆上分配。

第二个问题——当你打电话时:

sprintf(szData[i][0], "Williams%d", 0);

您正在覆盖您提供的内存的边界。请记住,您的缓冲区只有"Williams" 字节数(加一)!您没有空间在结尾处添加整数的字符串表示形式。使用sprintf_s 并确保您的缓冲区有足够的空间!

第三个问题 - 写入静态分配的字符串数据非常粗略,可能并非在所有情况下都有效。

底线:为所有内容动态分配正确大小的缓冲区,您的代码将正常工作。

这是一个修复该部分代码的简单示例。它演示了修复代码的概念,但它并不真正适合您的代码库,您需要正确地使用它。

const size_t MAX_NAME_LENGTH = 15; // Fix this magic number to be whatever max name length you want
char *s = new char[MAX_NAME_LENGTH];  // allocate on heap
strcpy_s(s, MAX_NAME_LENGTH, "Williams");  // use strcpy_s for safety
     
szData[i][0] = s;
sprintf_s(szData[i][0], MAX_NAME_LENGTH, "Williams%d", 0);  // use sprintf_s for safety

【讨论】:

  • strcpy_ssprintf_s 在标准 C++ 中是可选的(许多编译器可能不提供)