ovvvol
ovvvol

Reputation: 25

Changing sprintf to an array of characters C++

I have a 2d array of words.

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);
    }
...
}

While assigning data, I tried to change this

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

to this

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

Why do I keep getting the message that my project "has trigerred a breakpoint"?

Is there any alternative to sprintf using array of characters? Cannot use string (one of the condition of this task)

Also, not so necessary, but if I delete 0 at the end here

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);

there will appear some numbers after every word. For example: Williams3937516. Why is that?

Full code:

#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;
}

Upvotes: 1

Views: 222

Answers (1)

Tumbleweed53
Tumbleweed53

Reputation: 1551

If you trace back the assignment of this pointer:

char s[] = "Williams";

You'll find you are attempting to free its memory here:

delete[] szData[i][j];

However, you can't do that -- the string "Williams" was never allocated with new, so it can't be freed with delete. In fact, it's statically allocated, in your binary. So the heap complains, and that's the cause of the breakpoint.

If you're going to delete everything in szData, you need to make sure it's all allocated on the heap with new.

Second problem - when you call:

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

You're overwriting the bounds of the memory you supplied. Remember, your buffer only has "Williams" number of bytes (plus one)! You don't have space to tack an integer's string representation on the end of that. Use sprintf_s and make sure your buffers have enough room!

Third problem - writing to statically allocated string data is enormously sketchy and may not work in all cases.

Bottom line: dynamic allocate a buffer of the right size for everything, and your code will work.

Here's a simple example to fix that section of code. It demonstrates the concepts that fix your code, but it's not really appropriate for your codebase as-is, you'll need to work it in properly.

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

Upvotes: 1

Related Questions