c++ dynamic allocation of char * - c++

I have a problem in the following piece of code, the problem simply is that values of the dynamically-allocated array of char* changes from line number 24 to line number 28 and I can't figure out why
Code:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <ctype.h>
#include <cstring>
using namespace std;
int main() {
string x = "5+90-88n";
unsigned int i =0, k=0, argc=0;
char** argv = new char*[x.length()];
while (i < x.length()) {
if (isdigit(x[i])) {
k=0;
while (isdigit(x[i+k])) {k++;}
argv[argc] = (char*)x.substr(i,k).c_str();
i+=k;
} else {
argv[argc] = (char*)x.substr(i,1).c_str();
i++;
}
cout << argc <<" "<< argv[argc] <<endl;
argc++;
}
cout << " ------ \n";
for (unsigned int kk =0; kk<argc; kk++) {
cout << kk << " " << argv[kk] << endl;
}
return 0;
}
Output :
0 5
1 +
2 90
3 -
4 88
5 n
------
0 n
1 n
2 n
3 n
4 n
5 n
I was expecting the upper and lower parts to be the same, being not the same means that even there is some mistake I did and didn't notice or there is something I don't know about using dynamic allocation.

The array pointed to by the pointer returned std::string::c_str is owned by the string. substr returns a temporary string object that goes out of scope at the end of the expression in which substr was called.
Taken together these two facts mean that the arrays pointed to by the pointers in argv get deleted immediately after you create them. By the time you get around to printing any of them they are long dead.

It seems a simple problem, but it doesn't actually, It took me hours to try to find the answer.
Let us see this code below:
int main()
{
const char* p;
const char* p1;
{
string x = "xt";
p = x.substr(0, 1).c_str();
cout << p << endl;
p1 = x.substr(1, 1).c_str();
cout << p1 << endl;
}
cout << p << endl;
cout << p1 << endl;
return 0;
}
Its output is:
x
t
t
t
When running in the {} scope, p and p1 are pointing to temporary variables, and now these variables are existing, so we can print p an p1 out. When the code running out of the {} scope, those temporary variable are inexistent, we just cannot refer to them again, but their memory and data are still existent. So we still can print the value of p and p1 out without a memory crash.
But why the value of p and p1 are the same?
Let us see this:
int main()
{
const char* p;
const char* p1;
{
string x = "xt";
string t1 = x.substr(0, 1);
p = t1.c_str();
cout << p << endl;
string t2 = x.substr(1, 1);
p1 = t2.c_str();
cout << p1 << endl;
}
cout << p << endl;
cout << p1 << endl;
return 0;
}
Its output is:
x
t
x
t
just as you expected.
Maybe there is something strange with substr. But I am not sure about it. I'll go on checking.
And, as the code shows above, p and p1 are pointing to different temporary variables, according to the different outputs, p and p1 may be pointing to the same temporary variable in the first example.
Let us back to your code, char** is pointers to pointers, It is wrong to frequently make a pointer point to a temporary variable.
My suggestion is that you might use a array of string instead of a array of pointer.
Hope that helps.

You are not allocating anything for the temporary sub-string string object created which creates a temporary pointer to an array.
Doing something like this should work but won't recommend as you can't free that memory anymore:
argv[argc] =(char*)((new string(x.substr(i,k)))->c_str());
You need the string object to survive as c_str returns a constant pointer to the string object's value. If string object doesn't exist, what will be that pointer pointing to? Read this: c_str cplusplus.com
It is recommended to store the sub-strings to some array/vector, and then do necessary work with pointers.

#Mohamed Ibrahim, I think I have gotten the real reason of this problem that the two output are different.
Let us consider one problem at first:
What is happening when a temporary variable has ended its lifetime?
Please see this code:
int a1 = 9;
int& a = a1;
{
int b = 10;
a = b;
cout << a << endl;
int c = 11;
count << a << endl;
}
cout << a << endl;
its output is:
10
11
11
But as we know, 'b' and 'c' has gone when we try to print 'a' out at the last time. Why does 'a' still hold a value?
The reason is the memory and data of 'b' and 'c' is still existing in spite of 'b' and 'c' have gone. 'a' is a reference, it refered to the memory of 'b' and 'c'.
Let us continue considering:
When will the memory and data of a temporary variable be swept?
Even a temporary lifetime has been ended, but its memory and data are still existing until another temporary variable is declared, and the value of the new varialbe covers the value the old variable in that memory, and then all of the pointers and the references who are refering to the old variable, their value has been changed, we can print their value out to prove.
So, in your code, a new temporary variable of string will be declared in each loop, despite you can print a correct value out, but the new variable has covered the old. After the while scope ended, only one variable's value is existing, it is the last variable you declared, all of the others have been covered. So, we just could see the same value in the last output.
The way to remain every value is to save it in a global variable:
int main()
{
string x = "5+90-88n";
unsigned int i =0,k=0,argc=0;
char** argv = new char*[x.length()];
while ( i< x.length())
{
if (isdigit(x[i])) { k=0;
while(isdigit(x[i+k])) {k++;}
char* temp = (char*)x.substr(i,k).c_str();
argv[argc] = new char[strlen(temp) + 1];
memset(argv[argc], 0, sizeof(argv[argc]));
strcpy(argv[argc], temp);
i+=k;
}
else {
char* temp = (char*)x.substr(i,1).c_str();
argv[argc] = new char[strlen(temp) + 1];
memset(argv[argc], 0, sizeof(argv[argc]));
strcpy(argv[argc], temp);
i++;
}
cout << argc <<" "<< argv[argc] <<endl;
argc++;
}
cout<<" ------ \n";
for( unsigned int kk =0;kk<argc;kk++) { cout <<kk <<" "<<argv[kk]<<endl; }
return 0;
}
the above code could work well, but it is unsafe, I don't like this way of coding.
My suggestion, as I have ever said, don't try to make a pointer point to a temporary variable, never do that. No offence, please correct your code.

Related

Pointers and the New Operator

I'm working on an exercise and can't seem to figure out what's going wrong. The prompt reads, "The variable cp_arr has been declared as an array of 26 pointers to char. Allocate 26 character values, initialized to the letters 'A' through 'Z' and assign their pointers to the elements of cp_arr (in that order)."
Edit: this post was flagged as a duplicate to a post involving pointers and strings, this isn't the same issue.
While testing the code, this is what I've come up with, but the output isn't exactly what I was expecting.
#include <iostream>
using namespace std;
int main()
{
char next = 'A';
char* cp_arr[26];
for (int i = 0; i < 26; i++)
{
cp_arr[i] = new char(next);
cout << cp_arr[i] << endl;
next++;
}
system("pause");
}
cp_arr[i] is a pointer-to-char, which is interpreted (by deeply-embedded convention) as a C string pointer. If you want to output just the one char it points to, do that:
cout << *cp_arr[i] << endl;

Extra number while looping through an array in C++

I am trying to loop through an array of integers using pointers using the following code:
#include <iostream>
int main (int argc, char ** argv)
{
int ar[] = {1,1,2,3,5,8,13,21,34,55};
char s[] = "string";
std::cout << "Print fibonacci until ten using pointers" << std::endl;
for (int * p = ar; *p; p++)
{
std::cout << *p << std::endl;
}
// for (char * cp = s; *cp; cp++)
// std::cout << "char is " << *cp << std::endl;
return 0;
}
On running this code, I get all 10 elements plus a number, 4196368.
But on uncommenting the second for-loop and running it again, the numbers vanishes.
Can someone explain why this happens? If needed, the code is compiled in a 64-bit Linux box.
You're lucky the loop stopped at all; you could have blown up your entire neighbourhood!
Your loop expects to find a "zero" to terminate the array iteration, but your array doesn't have one. Thus, your loop will just keep incrementing past the end of the array until god knows what. The practical results depend on too many practical factors to be either predictable or usefully explained.
I presume that this is an exercise, because using "null-termination" to iterate over an int array is mighty peculiar. In reality you'd just write:
for (auto x : ar)
std::cout << x << '\n';
}
You are invoking an undefined behavior.
The first for loop's termination condition is *p. So it is trying to access memory past what actually is owned by ar. Your loop then runs until it finds a memory location that contains 0 (read false) before terminating. In your case, it ran just one extra time (lucky you!). At my end, it ran four more times before terminating.
You must loop only as many times as the size of the array, which is sizeof(ar)/sizeof(ar[0])
Ensure that you have terminated zero:
int ar[] = {1,1,2,3,5,8,13,21,34,55, 0};
Well, actually this will result in a different outcome on a different machine or a different condition. The one that causes this is your for statement
for (int * p = ar; *p; p++)
{
std::cout << *p << std::endl;
}
Here, you used *p as a conditional for your for loop to keep running. As we know, C++ treat number > 0 as a true and 0 as a false. While in the for statement, your program checks the next memory address if the value in that address is zero or not (True or False). And as you know, the value of the next address in this particular case on your particular PC is 4196368. So the for loop keeps going until the value of the next address is zero. You can see this with printing the address.
for (int * p = ar; *p; p++)
{
std::cout << *p << " " << p << std::endl;
}
You will know here that your code check the next address to see its value an if it is indeed not zero, it will continue the loop.

A simple vector, how can I reassign the address for a new array correctly

I am trying to create a simple version of a vector. It seems to be working if I look only at what I am storing, but there is one thing that concerns me. Here is my code:
#include <iostream>
using namespace std;
int main(){
char* arr = new char[1];
int size = 1; // current size of the array
int num_chars = 0; // how many characters are stored so far
char c;
while (true)
{
cout << ">";
cin >> c;
if (c == '!') break;
if (num_chars == size)
{
size *= 2;
char* new_arr = new char[size];
cout << "Old array address: " << &arr << endl;
cout << "New array address: " << &new_arr << endl;
for (int i = 0; i < size/2; i++) // copy arr to new_arr
new_arr[i] = arr[i];
delete[] arr;
arr = new_arr;
}
arr[num_chars++] = c;
for (int i = 0; i < num_chars; i++)
cout << arr[i];
cout << endl;
cout << &arr << endl;
}
delete[] arr;
return 0;
}
the program accepts characters one at a time, and they are stored in an array which grows dynamically, finishing when you enter an exclamation mark. I added some cout statements to check my input and where the arrays are being stored.
When I allocate new_arr it gets a new address, then I copy over the memebers of arr to the new arr, delete arr, and assign arr to point to new_arr. The part that concerns me is that when I check the memory locations of arr after it gets reassigned, it's the same as it was before, so it looks like I'm just writing past the end of the original array. How can I correctly reassign the pointer to the new array?
Here is some sample output:
>a
a
0x7fff5fbff760
>b
Old array address: 0x7fff5fbff760
New array address: 0x7fff5fbff748
ab
0x7fff5fbff760
>c
Old array address: 0x7fff5fbff760
New array address: 0x7fff5fbff748
abc
0x7fff5fbff760
You are printing out addresses of pointers themselves, not addresses of the arrays (i.e. the contents of the pointers).
The location in memory where you store the address of the array (i.e. the address of variable arr) stays the same. It's not supposed to change. Thus, &arr is always the same. But the value stored in that location does change (as it would be expected).
Change the code to
cout << "Old array address: " << static_cast<void*>(arr) << endl;
and see the difference.
(static_cast<void*>(arr) casts type of arr from char* to void*. The reason to do this is that cout treats char* as a pointer to null-terminated string, and prints the contents of the string instead of the pointer's value. However, if we change the type of the pointer to something that cout does not interpret (e.g. void*), then cout will just print the address.)

How to return a string from a function?

I made this little program just to get better understanding of dealing with strings.But i stuck in a small problem. Here is the code.
#include<iostream>
#include<string>
using namespace std;
string& add( string&x ){
string t; // <= Is this the problem???Declaring local string variable
cout <<"Size of String :" <<x.size() << endl;
for(int i=0; i<x.size();i++){
int n = x[i] - '0';
t[i] = n + 2 + '0';
}
for(int i=0;i<x.size();i++)
cout <<"t["<<i<<"]="<<t[i]<<endl; //This line is showing output as I wanted
cout <<"\nt = " << t << endl; // <=why the output of this line is blank?
cout <<"size of t="<<t.size() << endl; // <=and why the size of string t is zero?
return t;
}
int main(){
string a;
cin >> a ;
string b = add(a);
cout << "b =" << b << endl;
system("pause");
return 0;
}
I/p :123
o/p:
size of String :3
t[0]=3 t[1]=4 t[2]=5
t=
size of t = 0
b =
I am having problem with referencing the variable, passing the string as a reference and returning the string..
can anybody help me ??
Yes, it is a problem. You end up with a dangling reference. At the exit from the function, the local string t is destroyed, and the returned reference end up referring anything that happens to be at the memory location where t was. Using it later will cause undefined behaviour.
Just return the string by value
string add( /* const */ string&x ) // should use `const` probably if you don't modify x
the compiler is smart enough to avoid un-necessary copies (see copy elision).
PS: You should use += operator to append a char to a string, that is, replace t[i] = n + 2 + '0'; by t[i] += n + 2 + '0';. std::string is a class and the [] operator is used to read/write from an INITIALIZED string (you cannot append by incrementing the counter past the end of the string, and you initial string has length 0). Use its overloaded operator += to append.
I believe using useful functions like itoa and atoi is the best way to convert between integers and strings and its so easier too.
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
string add( char * x ){
int n = atoi(x) + 2;
char m[10];
itoa(n, m, 10);
return m;
}
int main(){
char a[10];
cin >> a ;
string b = add(a);
cout << "b =" << b << endl;
system("pause");
return 0;
}
After its string t; declaration, t is the empty string. So you are not allowed to assign values to t[0],t[1] etc -- they don't exist. (Technically, t[0] exists as the null terminator of t.cstr(), but let's not go there.)
After your illegal assignments to t[i], the length is still zero. You were lucky not to generate an access violation !

Char array not destroyed after function returns [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 10 years ago.
In the code below, i expect tmp character array to be destroyed after f() returns and hence x should not be printed at all.
However, in the below function x get printed in main() but the for loop does not print the correct thing. Could someone explain this behavior. Here is the output.
abcdefg
a
b
c
d
e
f
g
abcdefg
?
k
Y
i
#include <iostream>
using namespace std;
char* x;
void f()
{
char tmp[100]= "abcdefg";
x = tmp;
cout << x << endl;
for(int i=0; i < 7; i++)
cout << x[i] << endl;
}
int main()
{
f();
cout << x << endl;
for(int i=0; i < 7; i++)
cout << x[i] << endl;
}
What you are doing is undefined behaviour, you have a pointer pointing to a memory location that may or may not be in tact. This is bad.
What is actually happening is that you char buffer tmp is located on the stack frame for function f(), when that function returns the data is left on the stack to be over written by future stack frame.
The correct way of doing what you have done is simply.
std::string f() {
std::string str ("abcdefg");
std::cout << str << '\n';
return str;
}
int main() {
std::string s=f();
std::cout << s << '\n';
}
You are invoking undefined behaviour. The pointer may or may not be valid after f() scope closes.
You are invoking UB. You access memory that is no longer allocated for your program. It is mere luck it works on the first print.
In your program x is defined to be a global pointer which is initialized with an address on the stack as char temp[100] is allocated on the stack. When the function f returns, the stack pointer is decremented. However, x will continue to point to the same memory location which will not have the correct values and hence, incorrect output is observed.