Returning Character Array via Assignment Operator - c++

So this is a homework assignment, there might be come constraints that are ridiculous but please bear with me. This is just a simple function but drawn out. I need to return a character array via assignment operator but it doesn't seem to be working at all. I've tried pointers, but no luck.
#include <iostream>
using namespace std;
char* findMax(char*, char*);
int main()
{
char aArray[50] = "Hello World",
bArray[50] = "dlroW olleH",
maxArray[50];
maxArray[50] = findMax(aArray, bArray);
cout << maxArray << " is the bigger of the 2 strings" << endl;
return 0;
}
char* findMax(char* strA, char* strB){
char* maxStr;
if(strcmp(strA, strB) < 1)
maxStr = strB;
else
maxStr = strA;
return maxStr;
}
if I cout the return value of findMax() it does print out the value of bArray, but geting it into maxArray via assignment operator isn't working at all.

There are two ways to do this. As written, maxArray is an array of characters. Arrays can't be directly assigned to. Instead you need to copy each character one by one. You could do that with a loop, or by calling the strcpy standard library function.
char maxArray[50];
strcpy(findMax(aArray, bArray), maxArray);
The other way is to change the declaration of maxArray to be a char *, a pointer. Pointers can be assigned to directly without having to loop or invoke a function.
char *maxArray;
maxArray = findMax(aArray, bArray);
The difference between this and the first solution is subtle, but important. With char maxArray[50] you are actually allocating a third array of 50 characters, separate from aArray and bArray. This array has its own storage, its own 50 bytes of memory.
In the second you don't create a third array. You merely create a pointer which can point to other arrays already in existence. After the assignment, maxArray becomes an indirect reference to either aArray or bArray. It's not a copy of one of those arrays, it points to one of them.

Related

How could I use a reference of a pointer when re-allocating memory?

Unlike in the C, as what i've learned about C++, there is no instruction realloc in C++ for it is not recommended. But when I was creating a function that concatenates strings and at the same time can be dynamically re-allocating the given strings' memory without using vector, I've come to need some code just like as the realloc instruction functioning.
So what i've come up with is that using a reference of a pointer(in the code char* &des) could adjust the size of memory by using the usual instruction of C++, new and delete. However, an error occured: "[Error] invalid initialization of non-const reference of type 'char*&' from an rvalue of type 'char*'" Why is it impossible to initialize char*& type with the type char*? Isn't it the same as a statement char* &des = str0? The total code is as follows:
void Mystrcat(char* &des, const char* src) {
int des_len = Mystrlen(des); // Mystrlen just returns the length of a string with the type unsigned int excluding null character
int src_len = Mystrlen(src);
char* temp_str = des;
des = new char[des_len + src_len + 1];
//a copy process
for(int i = 0; i < des_len; i++) {
des[i] = *(temp_str + i);
}
for(int i = des_len + 1; i < des_len + src_len + 1; i++)
des[i - 1] = *(src + i - des_len - 1);
}
int main() {
char str0[100] = "Hello";
Mystrcat(str0, ", World!");
std::cout << str0 << std::endl; //expecting "Hello, World!" to be printed
return 0;
}
What i've tried before is just writing the parameter char* des instead of char* &des. But unlike in main function, it was not possible to get the size of total str0 array in Mystrcat function by simply using sizeof. As a result, I thought it would be good to use pointer reference. I was expecting this a reference of a pointer parameter to be working properly because it is equal to the statement char* &des = str0.
The problem here is:
char str0[100] = "Hello";
str in this case has a pinned (static) memory address. It's immutable in terms of its address -- so to speak -- because it's not a pointer to a string, but an array of characters of a size that can be evaluated at compile-time (not dynamically allocated). Making str itself point to a different address makes no sense and invites a whole lot of chaos. Even modifying the original pointer address to a dynamically-allocated array is chaos since you need the original address to properly free it. Think of an array of T as T* const (the address is immutable even if the contents are mutable and even if dynamically allocated, you need to keep the original address unmodified).
But in general as a non-profit advertisement of sorts, I want to encourage embracing value semantics as much as you can over pointer/reference ones. So instead of:
void Mystrcat(char* &des, const char* src)
{
// Modify the address of 'des' in place.
}
You can do:
[[nodiscard]] char* Mystrcat(char* des, const char* src)
{
// Input an address to a string and return an address to a new string.
}
Then you can pass an address to your array, get a pointer to a new modified copy (same thing you were doing before), and store the pointer to the new array (along with freeing it when you're done). There's little benefit to modifying things in place if you're just going to allocate a new string anyway.
This is still ignoring the conventional advice that you should use std::string which is what I think you need now and wholeheartedly echo over all this low-level pointer stuff and manual heap allocation and deallocation (which can be disastrous without the use of RAII when combined with thrown exceptions) But later you might want to deviate from it if the SBO is too large or too small or if the SBO optimization is counter-productive, for example but that's diving deep into things like custom memory allocators and whatnot and something you typically reserve until you encounter profiler hotspots and really know what you're doing.

How to use double pointers in array

I am in a problem in which I have to write a function which will tokenize the array of characters and then return the array.... I cannnot understand how to use double pointers... The whole code is here:
#include<iostream>
using namespace std;
char** StringTokenize(char*);
int main()
{
char *string1=new char[50];
cout<<"Enter: ";
cin.getline(string1,50);
StringTokenize(&string1[0]);
return 0;
}
char** StringTokenize(char *string1)
{
int i = 0, j = 0;
char **tokenArray[50];
**tokenArray[0] = &string1[0];
while (string1[i] != '\0')
{
tokenArray[i] = string1[i];
i++;
if (string1[i] == ' ')
{
tokenArray[i] = '\n';
i++;
}
else
{
continue;
}
}
tokenArray[i] = '\0';
cout << tokenArray << endl;
return tokenArray;
}
Please help me and write this function for me... Remember that prototype of function should not change
and then return the array.
In C++, return type of a function cannot be an array.
char *string1=new char[50];
It's a bad idea to use bare owning pointers to dynamic memory. If the program compiled at all, you would be leaking memory. I recommend using std::string instead.
StringTokenize(&string1[0]);
&string1[0] is redundant. You indirect through a pointer, and then get the address of the result... which is the pointer that you indirected through.
int i = 0, j = 0;
You've declared j, but aren't using it for anything.
char **tokenArray[50];
The pointers to substrings should be pointers to char. It's unclear why your array contains pointers to pointers to char.
Note that these pointers are uninitiallised at the moment.
**tokenArray[0] = &string1[0];
**tokenArray[0] will indirect through the first uninitialised pointer and the behaviour of the program will be undefined. And the right hand side has the aforementioned redundancy.
And the types don't match. The type of left hand operand is char while the type of right hand operand is char*. This is ill-formed and meaningless. Your compiler should be telling you about bugs like this.
tokenArray[i] = string1[i];
tokenArray[i] = '\n';
tokenArray[i] = '\0';
The types don't match. The type of left hand operand is char** while the type of right hand operand is char. These are ill-formed and meaningless. Your compiler should be telling you about bugs like this.
return tokenArray;
This is wrong because
The types don't match. You're supposed to return a char**, but tokenArray is an array of char**.
Returning an automatic array would result in implicit conversion to pointer to first element (which is a char***) and the automatic array would be automatically destroyed after the function returns, so the returned pointer would be invalid.
prototype of function should not change
That's rather unfortunate since it prevents writing a well designed function. You will either have to use static storage for the array, or return an owning bare pointer to (first element of) dynamic array. Neither is a good idea.

How do I correctly work with char pointer to array in C++?

I am trying to pick up my C++; I have basic understanding of pointers and references; but when it comes to char pointer to array, it seems nothing works for me.
I have a small piece of codes here (omitted include and namespace statements), I have included my questions as comments below:
I have gone through at least 5 other questions on SO to try to understand it; but those answers didn't the answer I expected and to the extent that could help understand the actual issue there.
Could you kindly explain the problems I commented below with a bit of depth from the surface (so please don't dive into it directly)?
int main(){
// 1 this is a char pointer to a char;
char * c = new char;
*c ='A';
cout << c << endl; // this gives me memory address;
cout << *c << endl;// this gives me the value in the memory address;
// 2 this is a char array initialised to value "world";
char d[6] = "world";
cout << d[0] << endl; // this gives me the first element of char array;
// 3 this is char pointer to char array (or array of char pointers)?
char * str = new char[6];
for(int i=0;i<6;i++){ //
str[i]=d[i]; // are we assigning the memory address (not value) of respective elements here?
} // can I just do: *str = "world"; what's the difference between initialising with value
// and declaring the pointer and then assign value?
char * strr = "morning";
char b[6] = "hello";
cout << b << endl;
cout << (*str)[i] << endl; // why? error: subscripts requires array or pointer type
cout << str[1] << endl;
cout << (*strr)[1] << endl; // why? error: subscripts requires array or pointer type
}
// 1 this is a char pointer to a char;
Right.
// 2 this is a char array initialised to value "world";
Right, "world\0" is created by the compiler and is put in the read-only memory area of the program. Note that this is called a string literal. Then the string is copied over to the char array d.
// 3 this is char pointer to char array (or array of char pointers)?
That's a char pointer yes, a pointer to a single char.
// are we assigning the memory address (not value) of respective
elements here?
No, you're assigning the values of the elements. This is allowed because str[i] is the same as *(str + i) so you can use the same "array style" access with the pointer str. You're looping over the individual chars you have allocated with new and are assigning them the value of the chars in the char array d.
// why? error: subscripts requires array or pointer type
Because you already dereference str (which is pointing at the start of the 6 element char array) with * which gives you a char, then you try to use that char like an array with [1] which makes no sense. *str would give you 'w' (the first element). And str[1] would give you *(str + 1) which is 'o' (the second element), don't double up.
A small-big side note, string literals are of type const char[], not char[], they're placed in read only memory and thus they can not be altered by the program (don't write to them).
char * strr = "morning";
This is very very bad, it treats a const char[] as a char[], this has been deprecated in the standard for a while now and according to the current standard this is even illegal, yet compilers still allow it for some reason.
Because compilers allow this you could get some nasty situations like trying to modify the string literal:
char * strr = "morning";
strr[0] = 'w'; // change to "worning"
This will attempt to write to read-only memory, which is undefined behaviour and will probably/hopefully get you a segmentation fault. Long story short, use the appropriate type to have the compiler stop you before the code reaches runtime:
const char * strr = "morning";
side side note : don't forget to delete anything you allocated with new.

Returning two dimensional array of strings

string** flowFile() {
string line;
string word[8];
int i=0;
static string flow[23][2];
ifstream myfile ("test.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
strSplit(line,word);
flow[i][0]=word[1];
flow[i++][1]=word[2];
}
myfile.close();
}
else cout << "Unable to open file";
return flow;
}
int main()
{
string **fl=flowFile();
}
I'm getting this error:
error: cannot convert ‘std::string (*)[2] {aka std::basic_string<char> (*)[2]}’
to ‘std::string** {aka std::basic_string<char>**}’
in return
What is wrong with my code?
string flow[23][2] and string ** are two different incompatible types. One cannot convert to another implicitly. Thats all. The solution is to make them compatible, by making the later string [23][2], return reference and accept reference, but that would still be a bad solution, because you're still working with raw arrays.
A good solution is to use std::vector and std::string. Maybe, you need std::pair also, or std::array.
Here is one possible solution:
#include <vector>
#include <array>
#include <string>
//C++11 style typedef
using flow_data_t = std::vector<std::array<std::string,2>>;
//reimplementation of your function
flow_data_t flowFile()
{
std::string line;
std::string word[8];
int i=0;
flow_data_t flow;
std::ifstream myfile ("test.txt");
if ( !myfile )
cout << "Unable to open file";
while ( std::getline (myfile,line) )
{
strSplit(line,word);
flow.push_back({word[0], word[1]});
}
return flow;
}
int main()
{
flow_data_t data=flowFile();
for(auto const & row : data)
for(auto const & col : row)
//work!
}
Hope that helps.
You cannot return array from a function even though you can return a pointer and let your array decay to a pointer: Array Decay
However 2D array can decay to neither T* nor T** because of the memory layout of the array is different from "2D pointer array" (it is actually more like flattened), and you cannot return array from function. However in C++ you can return array reference Full Code:
//This does not work
//typedef string * string2d[2];
//typedef string *(&string2d)[2];
typedef string (&string2d)[23][2];
string2d flowFile() {
static string flow[23][2];
return flow;
}
Array reference would even preserve the information of how big each row and columns are and no array decaying happen.
Of course, a more suggested "C++ way" to do this is using std::vector (as always).
In C++, arrays have type std::vector. You should use these, not low-level builtin arrays declared with [].
In C++, string [23] is sometimes interchangeable with string*, but string[23][2] is never interchangeable with string**. That's one reason you should not use builtin arrays.
In C++, you cannot return a local builtin array variable. It will compile but then your program will probably crash. This is another reason you should not use builtin arrays. (Returning a static array should be OK though).
There are many more reasons.
There is nothing wrong with returning a pointer to a static variable. It's just that the return type must be declared properly. It kind of makes sense if you try to reproduce what the declarations mean, and what the compiler accordingly tries to do. Consider the declaration static string flow[23][2];. It declares 23 rows of strings, each with 2 elements. It helps if you look at it as a one-dimensional array. It just so happens that the array elements are arrays, but that's not so important right now (but we'll come back to it). From this perspective the array has just 23 elements, and each element has the size of 2 strings. Like with all arrays, the elements (here: arrys of 2 strings) are simply lined up in memory.
Like any array, flow will in most contexts decay to a pointer to its first element. Incrementing that pointer will point to the next element, i.e the second row. Numerically the compiler must add 2*sizeof(string) to the address of flow in order to compute the address of flow's next element, which would be flow[1]. (It comes directly behind flow[0]. No magic here.)
Now if you declare string **flowpp, flowpp is a pointer already, no need to decay. If we think it is pointing to the first element in an array, what type would the elements have? Sure enough: plain pointers. Incrementing flowpp would let it point to the next element. My pointers are 4 bytes large, so that numerically adding just 4 to flowpp would be enough to access flowpp's next element. Compared to what needs to be added to flow (remember, 2*sizeof(string)), that's completely different. The compiler computes the offsets of elements depending of what the pointers point to! Which is very different in the two cases.
So what can your function return? What does flow decay to when you return it? It decays to a pointer to its first element. The elements are arrays of two strings. It must be string xxx[2], with xxx being a pointer: hence string (*p)[2]. If the pointer is actually returned by a function, we have a function call instead of plain p, so it's (*f())[2].
Here is a complete example:
#include<iostream>
using namespace std;
const int numFlowElems = 3, numArrElems = 2;
/** #return a pointer to the first element of a static array
of string[numArrElems]s.
*/
string (*flowFile())[numArrElems]
{ // init so that we see something below.
static string flow[numFlowElems][numArrElems]
= {{"1","2"},
{"3","4"},
{"5","6"}
};
// your function code ...
return flow;
}
int main()
{
// array decays to ptr, like usual. Ptr elems are string[numArrElems].
// ptrToArr is a pointer to arrays of two strings.
string (*ptrToArr)[numArrElems] = flowFile();
for( int flowInd= 0; flowInd<numFlowElems; ++flowInd )
{
for(int strInd = 0; strInd<numArrElems; ++strInd)
{
cout << ptrToArr[flowInd][strInd] << ' ';
}
cout << endl;
}
return 0;
}
How do you parse string (*flowFile())[numArrElems]? I needed two attempts to get the declaration right, if that's any consolation. The key is that in C and C++ (not in C#, mind you!) a declaration has the shape of an expression.
You can do it from the inside to the outside: flowFile() is a function. The result is dereferenced because the function call has higher precedence than the star: *flowFile() is the dereferenced result. Apparently that result is an array of size numArrElems, with elements which are strings.
You can do it outside in: The result of (*flowFile())[numArrElems] is declared as a string. (*flowFile()) is an array of strings with numArrElems elements. Apparently flowFile() must be dereferenced to obtain that array so that flowfile is a function which returns a pointer to an array of numArrElems strings. That's true! It returns the first element of flow, which is exactly an array of strings.
Vectors of vectors might indeed be easier; if you want to retain the semantics you should pass references, as others mentioned: After all, all functions in your original program will operate on the same static array. If you pass vectors by value that will not be the case any longer. But then, that may actually be beneficial.

deprecated conversion from string constant to 'char*' [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C++ deprecated conversion from string constant to 'char*'
I want to pass a string via char* to a function.
char *Type = new char[10];
Type = "Access"; // ERROR
However I get this error:
error: deprecated conversion from string constant to 'char*'
How can I fix that?
If you really want to modify Type:
char *Type = new char[10];
strcpy( Type, "Access" );
If you don't want to modify access:
const char *Type = "Access";
Please note, that, however, arrays of char in C and in C++ come with a lot of problems. For example, you don't really know if the call to new has been successful, or whether it is going to throw an exception. Also, strcpy() could surpass the limit of 10 chars.
So you can consider, if you want to modify type later:
std::string Type = "Access";
And if you don't want to modify it:
const std::string Type = "Access";
... the benefit of using std::string is that it is able to cope with all these issues.
There are a couple of things going on here.
char *Type = new char[10];
This create a char* pointer named Type and initializes it to point to the first element of a newly allocated 10-element array.
Type = "Access"; // ERROR
This assignment doesn't do what you think it does. It doesn't copy the 6-character string "Access" (7 characters including the terminating '\0') to the array you just created. Instead, it assigns a pointer to the first element of that array into your pointer Type. There are two problems with that.
First, it clobbers the previous value of Type. That 10-character array you just allocated now has nothing pointing to it; you can no longer access it or even deallocate it. This is a memory leak.
This isn't what the compiler is complaining about.
Second, a string literal creates a statically allocated const array ("statically allocated" meaning it exists for the entire execution of your program). Type is not declared with a const qualifier. If the compiler allowed you to point Type to the string "Access", you could use that pointer to (attempt to) modify it:
Type = "Access";
Type[0] = 'a'; // try to change the string to "access"
The purpose of const is to prevent you from modifying, or even attempting to modify, things that are read-only. That's why you're not allowed to assign a non-const pointer value to a const pointer object.
Since you're programming in C++, you're probably better off using std::string.
I want to pass a string via char* to a function.
Here is how you can pass a string via char* to a function (note the required const keyword in the function signature.)
#include <iostream>
void f(const char* p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
But, what if you are invoking an existing function, and cannot modify its signature?
If you have some external guarantee that the function will not write through its argument pointer,
#include <iostream>
void f(char* p) {
std::cout << p << "\n";
}
int main() {
f(const_cast<char*>("Access"));
}
If, on the other hand, the function might write to the string, then you'll need to allocate space for the string:
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the heap
char *p = new char[strlen("Access"+1)];
// Copy string to allocated space
strcpy(p, "Access");
f(p);
delete p;
}
or,
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the stack
char arr[] = "Access";
f(arr);
}
But, the best course by far is to avoid the whole pointer mishegas:
#include <iostream>
void f(const std::string& p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
You've got a basic operations problem here, not a coding issue.
When you want to change the contents of a C char array, you do not use the assignment operator. That will instead change the value of the underlying pointer. Ick.
Instead you are supposed to use the C string library routines. For instance, strcpy (Type, "Access"); will copy the string literal "Access" into your character array, with its all-important trailing nul character.
If you are using C++ (as your tags indicate), you should probably be using std::string instead of arrays of char. Assignment works they way you are expecting there.