'char' array issue, custom print function and strcpy_s problem - c++

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!

Related

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

Return char[256] from an accessor of a char[256] attribute

class A{
char info[256];
public:
char* getInfo();
A(char i[256]);
//A.cpp
#include "A.h"
char * A::getInfo(){
return(&info[256]);
}
A::A(char i[256]){
info[256]=i[256];
}
I'm struggling with the accessor. When I try to use getInfo(), I get a char*, and thus with
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
I get
╠╠╠╠╠╠╠╠test
I guess I'm doing things the wrong way, but I cant figure it out..
By the way, VScode also warn me on
info[256]=i[256]
by telling me that 257 octets bytes might be written (C6386) but I dont get it ...
Could you help me please ? Thanks !
The problem is, your constructor is not initializing the contents of the info array correctly, and your accessor is returning a bad pointer.
In the constructor, info[256]=i[256] does not do what you think it does. You are trying to copy the 257th element of i into the 257th element of info, which is Undefined Behavior since neither array has 257 elements. That is why the compiler is warning you about it.
Try this instead:
A::A(char i[256]){
for(int x = 0; x < 256; ++x){
info[x] = i[x];
}
}
Alternatively:
#include <algorithm>
A::A(char i[256]){
std::copy_n(i, 256, info);
}
As for the accessor, it is returning a pointer to the non-existent 257th element. You need to return a pointer to the 1st element instead:
char * A::getInfo(){
return(&info[0]);
}
Or simply:
char * A::getInfo(){
return info;
}
This declaration of the constructor
A(char i[256]);
does not make a great sense because the compiler will adjust the parameter declaration like
A(char *i);
Taking into account this code snippet
char test[256] = "test";
FractionException d(test);
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
It seems you want that the constructor would accept a string. If so then it should be declared like
A( const char * );
and it can be defined like
#include <cstring>
//...
A::A( const char *i ){
strncpy( info, i, sizeof( info ) );
info[sizeof( info ) - 1] = '\0';
}
The member function getInfo should return the array instead of the address of the non-existent element info[256]
char * A::getInfo(){
return info;
}
This method should be also overloaded
const char * getInfo() const;
And this loop
for (int i = 0; i < 256; i++) {
cout << d.getInfo()[i] ;
}
should be substituted for this statement
std::cout << d.getInfo();

how to pass and retrieve char array in 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.

Class accept and return array

I try to create a class that accept and return an array but I got some problem. I'm not sure if it is legal to return an array from a class. Or it could be done by returning an pointer to the array. Thank for any solution to the problem.
#include <iostream>
using namespace std;
class myclass {
private:
int Array[10];
public:
myclass (int temp[10]) {
for (int i = 0; i < 10; i++) {
Array [i] = temp [i];
}
}
int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
int* returnArray2 () {
return this->Array; // hope it will return a pointer to the array
}
};
int main () {
int Array[10] = {1,2,3,4,5,6,7,8,9};
myclass A(Array);
cout << A.returnArray() << endl; // try to return an array and print it.
myclass* ptr = &A;
cout << *ptr->returnArray2 << endl; // error here
return 0;
}
First of all it is better to write the constructor either like
myclass ( const int ( &temp )[10] ) {
for (size_t i = 0; i < 10; i++) {
Array [i] = temp [i];
}
}
or like
myclass ( int temp[], size_t n ) : Array {} {
if ( n > 10 ) n = 10;
for (size_t i = 0; i < n; i++) {
Array [i] = temp [i];
}
}
Or even you may define the both constructors.
As for the returning value then you may not return an array. You may return either a reference to an array or a pointer to the entire array or a pointer to its first element
For example
int ( &returnArray () )[10] {
return Array;
}
In this case you can write in main
for ( int x : A.returnArray() ) std::cout << x << ' ';
std::cout << std::endl;
As for this statement
cout << *ptr->returnArray2 << endl; // error here
then you forgot to place parentheses after returnArray2. Write
cout << *ptr->returnArray2() << endl;
And the following member function is wrong because the expression in the return statement has type int * while the return type of the function is int
int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
So either the function will coincide with the the second member function if you specify its return type like int *. Or you could change the return expression to *Array
int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
This is illegal because Array is not of int type. Your returnArray2 is valid, however. As for this line:
cout << *ptr->returnArray2 << endl; // error here
This is illegal because returnArray2 is a function; you must call it to return the int*:
cout << *ptr->returnArray2() << endl; // prints the first value in the array
Other notes:
Your capitalization is backwards; you should call your class MyClass and your member array arr or arr_, or you will confuse a lot of people.
return this->Array; this is redundant, you can simply return Array;
If you haven't heard of std::vector and std::array you should research those, as they are generally superior to C-style arrays.
In general, I would suggest to read a c++ book to get your basics correct as there are lot of issues in the code you posted.
Regarding your main question about exposing C style arrays in class public API, this is not a very robust mechanism. Do it if it is absolutely essential because of existing code but if possible prefer to use std::vector. You will mostly always end up with better code.
Other answers have corrected your coding errors, so i won't repeat that.
One other thing, your code suggests that the array size is fixed. You can pass and return the array by reference as well. Refer to: General rules of passing/returning reference of array (not pointer) to/from a function?

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.