how to pass and retrieve char array in c++ - c++

I am trying to pass a character array to a function. Set the values onto a character array. Then retrieve it and print using another function. But not able to get the result. Here is the code
class cSummary{
private:
char *cSummaryTable[2];
public:
void printSummary();
void setSummary(char *ptr, int stage);
char *getSummary();
};
void cSummary::printSummary(){
char *cPtr = getSummary();
for(int i = 0; i < 2; i++){
cout << cPtr[i] << endl;
}
}
void cSummary::setSummary(char ptr[], int stage){
switch(stage){
case 0:
cSummaryTable[0] = ptr;
break;
case 1:
cSummaryTable[1] = ptr;
break;
}
}
char *cSummary::getSummary(){
return *cSummaryTable;
}
int main(int argc, char const *argv[])
{
cSummary summary;
summary.setSummary("first message!", 0);
summary.setSummary("second message!!", 1);
summary.printSummary();
return 0;
}

getSummary is the problem since it only returns the first string. Notice the assymmetry between getSummary and setSummary, setSummary has a stage parameter but there's no such parameter in getSummary. That should have been a clue that something was wrong. I would recode like this
char *cSummary::getSummary(int stage) {
return cSummaryTable[stage];
}
void cSummary::printSummary() {
for(int i = 0; i < 2; i++){
cout << getSummary(i) << endl;
}
}
And I'll add the obiligatory piece of good advice. You should learn to program modern C++, which doesn't use arrays and pointers, but uses the much safer and easier to understand std::string and std::vector instead.

Related

'char' array issue, custom print function and strcpy_s problem

I just started C++ and now I'm making a simple program. But don't know how to fix this problem.
I'm not a native english speaker so some sentences may not be understandable.
int main()
{
char test[5][4] = { "abc", "def", "ghi", "jkl", "mno" };
for (int i = 0; i < 5; ++i)
std::cout << test[i] << "\t";
return 0;
}
with this simple code, I made a print function
void printTest(char* pArr)
{
for (int i = 0; i < 5; ++i)
std::cout << pArr[i] << "\t";
}
Then in my main function, I typed printTest(*test);
but the result was 'a b c d'
while my expectation was 'abc def ghi jkl mno'
So I fixed printTest function like below
(changed const char* test[5][4] = { ... }
in main function)
void printTest(const char** pArr)
{
for (int i = 0; i < 5; ++i)
std::cout << pArr[i] << "\t";
}
which worked well.
The problem is, I want to use strcpy_s fucntion also.
strcpy_s(test[0], "xyx"); like this.
As strcpy_s get char* for the first parameter (not const char*),
I think I need to use char* for my array, and print function.
While that thing cause a wrong printing issue.
Did i wrote something wrong in my printTest function?
Or Is there any way that I can use strcpy_s function with const char* parameter?
PS. I used std::string and made it as I expected.
But I want to have a understanding and control of Char array.
I don't think void printTest(const char** pArr) will work with
char test[5][4].
The c++ compiler should refuse something like
void printTest(const char** pArr);
char test[5][4];
printTest(test);
Because test is a pointer to char [4],
while printTest() expects a pointer to char *.
You may have interesting in this function:
void printTest2(const char (*pArr)[4] )
{
for (int i = 0; i < 5; ++i)
std::cout << pArr[i] << "\t";
std::cout << "\n";
}
And the const keyword tells compiler (and what more important, the reader of your code) that "you won't modify the contents of 'pArr'". So compiler will not allow you to strcpy to pArr[i]. And this will compile and run.
void printTest3(char (*pArr)[4] )
{
for (int i = 0; i < 5; ++i)
{
strcpy(pArr[i], "123");
std::cout << pArr[i] << "\t";
}
std::cout << "\n";
}
...
printTest3(test);
I think you are a but confused about he use of const. Don't worry, it's happened to pretty much every one.
What's important to understand is that a non-const variable can be implicitly cast to a const variable at any time, but the reverse is not possible.
For your function PrintTest()
// Here, the const char** declaration is correct, your function only prints pArr,
// and the caller should not expect the function to modify his precious data.
// Another thing to remember: pArr is valid (and thus constant) only within
// the scope of PrintTest(). It simply does not exist anywhere else.
void printTest(const char** pArr)
{
for (int i = 0; i < 5; ++i)
std::cout << pArr[i] << "\t";
}
// this naturally allows printing of const and non-const data, as one would expects.
const char const_strings[2][4] = { "abc", "def" };
printTest(const_strings); // works!
// Note that if printTest() required a non_const pointer, the line above
// would not compile.
// const_strings being const, there is no way to modify it using strcpy_s();
// The code below also works fine,
char modifiable_strings[2][4] = { "tuv", "xyz" };
printTest(modifiable_strings); // works!
strcpy_s(modifiable_strings[0], "abc"); // is OK, because modifiable is not const.
printTest(modifiable_strings); // works, with different output!

Sending an array of pointers as an argument to another function

I'm writing a game script, sort of in vein of 80's Rouge. My problem is that I want to send a pointer, *p_pixel_grid[8192], to another function without changing it. The other function has to recall the grid via this pointer, it supposed to have access to that part of the memory. It is necessary to redraw the grid at a later stage. Im unable to find a way, or syntax, to send it further. Any suggestions?
char grid_pointer(char grid[8192]) *//this function is just a test function to check if I can send it a pointer as an argument*
{
for (int i=0; i<=8191; i++)
{
cout << grid[8192];
cout << "a";
}
}
void lvl_loader ()
{
FILE* plik;
switch(menu())
{
case 1:
{
plik = fopen("lvl 1.txt", "r");
break;
}
case 2:
{
plik = fopen("lvl 2.txt", "r");
break;
}
case 3:
{
plik = fopen("lvl 3.txt", "r");
break;
}
}
char pixel_grid[32][128];
for (int i=0; i<=31; i++)
{
for (int j=0; j<=127; j++)
{
pixel_grid[i][j] = fgetc(plik);
//cout << pixel_grid[i][j];
}
}fclose(plik);
char *p_pixel_grid[8192]; int pointer_counter=1;
for (int i=0; i<=31; i++)
{
for (int j=0; j<=127; j++)
{
p_pixel_grid[pointer_counter]=&pixel_grid[i][j];
cout << *p_pixel_grid[pointer_counter];
pointer_counter++;
}
}
grid_pointer(&*p_pixel_grid[8192]); //here, I want send this pointer to another function, possibly unchanged. The other function has to use that pointer to recall to data loaded from the .txt
}
void grid_pointer(char ptr[][128])
{
std::cout << ptr[0][1];
std::cout << ptr[10][10];
}
int main()
{
char pixel_grid[32][128];
pixel_grid[0][1] = 'a';
pixel_grid[10][10] = 'b';
grid_pointer(pixel_grid);
}
I'm not sure how true this declaration
is here char *p_pixel_grid[8192]; because arrays are implicitly converted to pointers to their first element.
That is, it is better to make char p_pixel_grid[8192];
Passing a pointer to the array char grid_pointer(char grid[8192]) to the function; Also performed a little incorrectly. The required syntax looks like this:
void grid_pointer(char ptr[][128])
And instead of passing two parameters to the function - the pointer and the size. It is advisable to use span, it describes an object that can refer to a continuous sequence of objects with the first element of the sequence in the zero position.
#include <span>
#include <iostream>
void grid_pointer(std::span<char> grid)
{
std::cout << grid.data() << std::endl;
}
int main()
{
char p_pixel_grid[8192];
p_pixel_grid[0] = 'a';
p_pixel_grid[1] = 'b';
grid_pointer(std::span{ p_pixel_grid });
}
DEMO

Create Dynamically Allocated Array of Pointers C++

I'm currently trying to dynamically allocate an array of character arrays and set values from another array of character arrays to the new dynamically array. When I print the values from the dynamically array I got some junk values and I can not understand where they come from.
Class -
class Class {
private:
char** courses;
int numberOfCourses;
public:
Class();
Class(const char** courses, int numberOfCourses);
~Class();
char** getCoursesList();
int getNumberOfCourses();
};
Constructor (allocate memory) -
Class:: Class(const char **courses, int numberOfCourses) {
if (numberOfCourses <= 0){
this->numberOfCourses = 0;
this->courses = nullptr;
} else{
this->numberOfCourses = numberOfCourses;
this->courses = new char*[numberOfCourses];
for (int i = 0; i < numberOfCourses; i++) {
cout << strlen(courses[i]) << endl; // 5
this->courses[i] = new char[strlen(courses[i])];
cout << strlen(this->courses[i]) << endl; // 22
strncpy(this->courses[i], courses[i], strlen(courses[i]));
}
}
}
getNumberOfCourses -
int Class::getNumberOfCourses() {
return this->numberOfCourses;
}
getCoursesList -
char **Class::getCoursesList() {
return this->courses;
}
Main -
const char *courses[] = {"test1", "test2", "test3" };
Class d1(courses,3);
for (int i = 0; i < d1.getNumberOfCourses(); i++) {
cout << d1.getCoursesList()[i] << endl;
}
Output -
[test1═²²²²▌▌▌▌▌▌l┴╓K▌] [test2═²²²²▌▌▌▌▌▌#┴2K▌] [test3═²²²²▌▌▌▌▌▌Y┴;K▌]
I would love to understand what I am doing wrong.
Look here as you may understand from the documentation, strlen function does not count \0 character which is end of the string. Hence it is not copied with strcpy function call, and cout does not encounter with \0. This is the reason of absurd characters in terminal output. While allocating memory for course names, allocate for one more char and add \0 end of the char array.

Breakpoint with 2D array of char pointers

Console application has triggered a breakpoint.
So I have this 2D char array of pointers which I'm also passing onto other functions but when I try to delete the array I get a breakpoint error. I'm guessing some functions are not properly saving the data behind the pointer.
void toevoegenL()
{
int keuze;
int index = 0;
int indey = 2;
char** text;
text = new char *[20];
for (int i = 0; i <20; i++)
text[i] = new char[10];
fillspacearray(text);
leverancier leverancier1;
leverancier1.levID = instellenL();
try
{
invoerschermL();
gotoxy(22, 5); std::cout << leverancier1.levID;
texteditor(22, 6, 4,text);
cout << text[2][3];
chararray_to_leverancier(leverancier1, text);
wegschrijvenL(leverancier1);
leverancier1.levID++;
invoerschermL();
gotoxy(22, 5); std::cout << leverancier1.levID;
updatenL(leverancier1.levID);
}
catch (const std::exception& e)
{
cout << "er is een fout gebeurt, u kunt opnieuw proberen"<<endl;
system("Pause");
invoerschermL();
gotoxy(22, 5); std::cout << leverancier1.levID;
}
for (int i = 0; i <20; i++)
delete[] text[i];
delete[] text;
}
this is the piece of code where the breakpoint happens.
delete[] text[i];
this line in particular.
I'm also not sure if I'm passing the arrays properly to the other functions.
like this:
void print2DArray(char** A, int width, int height)
or like this:
void print2DArray(char**& A, int width, int height)
As you have already realized, the problem is having passed 22 instead of 20 to gotoxy.
A way of preventing this in future code is to define those values as constants, whether it is by using #define or a static const variable (you can see arguments for each one of them in this other StackOverflow question: static const vs #define).
This way, you could do:
#define NUMBER_OF_STRINGS 20
#define LENGTH_OF_STRING 10
char** text;
text = new char *[NUMBER_OF_STRINGS];
for (int i = 0; i <NUMBER_OF_STRINGS; i++)
text[i] = new char[LENGTH_OF_STRING];
...
gotoxy(NUMBER_OF_STRINGS, 5);
EDIT: I misunderstood what you said the problem was in the comments to the question. I do not think the for loop with delete within it is the problem.

Dynamic Memory Allocation for Dictionary

Hi there I need to Build something like a dictionary and each word according to my code can have 100 meanings, but maybe it has only 5 meanings then I will be allocating 95 extra space for nothing or maybe it has more than 100 meanings then the program will crash, I know the vector class is very easy and could be good use of, but the task is almost building my own vector class, to learn how it works. Thus **meanings and some other stuff remain the same and here is my code, Also I know I am causing memory leakage, how can I delete properly? :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Expression {
char *word_with_several_meanings; // like "bank", "class"
char **meanings; // a pointer to a pointer stores all meanings
int meanings_ctr; // meanings counter
//-----------FUNCTIONS------------------------------------------------
public:
void word( char* = NULL );
void add_meaning(char* = NULL);
char* get_word();
int get_total_number_of_meanings();
char* get_meaning(int meanx = 0);
Expression(int mctr = 0); // CTOR
~Expression(); // DTOR
};
Expression::Expression(int mctr ) {
meanings_ctr = mctr; // Setting the counter to 0
meanings = new char * [100]; // Allocate Space for 100 meanings
}
Expression::~Expression() {
delete [] meanings; // Deleting the memory we allocated
delete [] word_with_several_meanings; // Deleting the memory we allocated
}
void Expression::word( char *p2c )
{
word_with_several_meanings = new char[strlen(p2c)+1];
// copy the string, DEEP copy
strcpy(word_with_several_meanings, p2c);
}
void Expression::add_meaning(char *p2c)
{
//meanings = new char * [meanings_ctr+1];
meanings[meanings_ctr] = new char[strlen(p2c)+1];
strcpy(meanings[meanings_ctr++],p2c);
}
char * Expression::get_meaning( int meanx )
{
return *(meanings+meanx);
}
char * Expression::get_word()
{
return word_with_several_meanings;
}
int Expression::get_total_number_of_meanings()
{
return meanings_ctr;
}
int main(void) {
int i;
Expression expr;
expr.word("bank ");
expr.add_meaning("a place to get money from");
expr.add_meaning("b place to sit");
expr.add_meaning("4 letter word");
expr.add_meaning("Test meaning");
cout << expr.get_word() << endl;
for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
cout << " " << expr.get_meaning(i) << endl;
Expression expr2;
expr2.word("class");
expr2.add_meaning("a school class");
expr2.add_meaning("a classification for a hotel");
expr2.add_meaning("Starts with C");
cout << expr2.get_word() << endl;
for( i = 0; i<expr2.get_total_number_of_meanings(); i++)
cout << " " << expr2.get_meaning(i) << endl;
Expression expr3;
expr3.word("A long test ... ");
char str[] = "Meaning_ ";
for (int kx=0;kx<26;kx++)
{
str[8] = (char) ('A'+kx);
expr3.add_meaning(str);
}
cout << expr3.get_word() << endl;
for(i = 0; i < expr3.get_total_number_of_meanings(); i++)
cout << " " << expr3.get_meaning(i) << endl;
return 0;
}
When you are allocating a multi dimensional array with new then you are allocating it with a loop, e.g.
char **x = new char*[size]
for (int i = 0; i < N; i++) {
x[i] = new int[size];
}
So you also have to delete it in this fashion:
for (int i = 0; i < N; i++) {
delete[] x[i];
}
delete[] x;
Thus when you're having arbitrary sizes of your array you'll have to store them somewhere for using them within the destructor.
delete [] meanings; // Deleting the memory we allocated
won't get rid of your memory allocated, only the pointers themselves.
To free up the actual memory, you will need to iterate through your meanings array, and delete [] each element in it.
Something like:
for (int i = 0; i < meanings_ctr; ++i)
{
delete [] meanings[meanings_ctr];
meanings[meanings_ctr] = NULL;
}
delete [] meanings;
--
For the problem of what to do if you get more than 100 meanings (or in general when your collection is full), the standard technique is to allocate a new array that is double the size (which you can do since it is dynamic), copy your existing collection into that one, and then dispose of your existing one.
I'd use a simple linked list (this is simplified, not complete and untested; also there should be proper getters/setters and stuff):
class Meaning {
char text[20];
Meaning *next;
Meaning(const char *text) : next(0) {
strcpy(this->text, text);
}
}
class Word {
char text[20];
Meaning *first;
Meaning *last;
Word(const char *text) : first(0), last(0) {
strcpy(this->text, text);
}
~Word() {
Meaning *m = first, *n;
while(m) {
n = m->next;
delete m;
m = n;
}
}
void AddMeaning(const char *text) {
if (last) {
last = last->next = new Meaning(text);
}
else {
first = last = new Meaning(text);
}
}
void print() {
printf("%s:\n\t", text);
Meaning *m = first;
while (m) {
printf("%s, ", m->text);
m = m->next;
}
}
}