Click to See Complete Forum and Search --> : Dyanmic Array


doumalc++
February 4th, 2003, 05:42 PM
Can someone give me a good and clear explanation of dyanamic array?

1. its syntax
2. when to use it
3. advantages and disadvantages

Thanks!

kuphryn
February 5th, 2003, 02:47 PM
One solution is a vector or a deque. Both are simple and practical.

Kuphryn

mwilliamson
February 5th, 2003, 06:14 PM
1.
char* pszDynArray = NULL;
unsigned int nSize = 30;
pszDynArray = new char[30];

2. When you are concerned about your memory usage, or don't know the size of the data you will be storing.

3. Come on, do your own homework!

PaulWendt
February 5th, 2003, 07:51 PM
Originally posted by mwilliamson
1.
char* pszDynArray = NULL;
unsigned int nSize = 30;
pszDynArray = new char[30];

2. When you are concerned about your memory usage, or don't know the size of the data you will be storing.

3. Come on, do your own homework!

mwilliamson is correct, but he neglected to mention a very
integral part of the equation:

delete [] pszDynArray;


Without that delete, a memory leak would occur.

--Paul

mwilliamson
February 5th, 2003, 09:00 PM
yeah, it seems I also forgot to use nSize ;)

char* pszDynArray = NULL;
unsigned int nSize = 30;
pszDynArray = new char[nSize];

doumalc++
February 5th, 2003, 11:12 PM
Thanks for the replies guys.

I got confused after reading a particular article and had started to think that dynamic array was something different than what I knew it to be.

And, yes kuphryn, I also use vector in lieu of dynamic arrays quite often and when appropriate.

To the other guys, I actually use a little more efficient method for creating dynamic arrays than what you've posted. See below:

char inFile[] = "";
cin>>inFile;
ifstream in(inFile);

No need for pointers and no need to define any array size.

:)

RobAnd
February 5th, 2003, 11:19 PM
What makes your think that your method is *more efficient*?

As a note, the methods above all allocate physical memory. What you are doing is creating a file and using the disk as your *memory*. Don't mean to burst your bubble... but disks are SLOW.

Btw, you have a buffer overflow in your code as well. In other words, you are overwriting something you probably do not intend to.

- Robert

doumalc++
February 5th, 2003, 11:41 PM
Originally posted by RobAnd
What makes your think that your method is *more efficient*?

As a note, the methods above all allocate physical memory. What you are doing is creating a file and using the disk as your *memory*. Don't mean to burst your bubble... but disks are SLOW.

Btw, you have a buffer overflow in your code as well. In other words, you are overwriting something you probably do not intend to.

- Robert

1. No my method does not use the disk instead of physical memory in particular. The creation of the file (inFile) serves a different purpose than you think. It has to do with the rest of the program. The code you should focus on is: char inFile[] = "";
The next code could have been something else.

2. Could you please expand on the buffer overflow issue?
You might have something there that I am not aware of, newbie as I am.

Thanks!

RobAnd
February 5th, 2003, 11:53 PM
Basically, any time you allocate a constant string (as you have), the compiler moves it to a string table in the process heap and allocates exactly enough space to fit the constant string. In your case 1 byte for the NULL terminating string. If you try to write to this address pointed to by the variable and you write more than 1 byte, you will have essentially overwritten memory you did not intend to. This is called a buffer overflow.

Now... imagine you use cin >> inFile... and the user types some insanely long string. You could potentially overwrite code that at some point will get called. When that code gets calls your application is most likely going to crash because it does not make sense anymore.

Worse yet, someone could enter just the right text to cause your application to execute "meaningful" code that does something malicious.

I guess what I am trying to say is, you are not allocating a dynamic array when using that code in C/C++. You are setting yourself up for problems.

- Robert

doumalc++
February 6th, 2003, 12:22 AM
That makes sense in some ways.

But isn't it a way to create dynamic arrays without declaring an array size?

In the following code:

char* pszDynArray = NULL;
unsigned int nSize = 30;
pszDynArray = new char[nSize];

you still are declaring an array size.
What happens when you input more than 30 char?

RobAnd
February 6th, 2003, 12:26 AM
There is no way to allocate a completely dynamic array. Arrays in C/C++ cannot grow by themselves. If you want this kind of functionality then use the vector class... or if you are daring... write your own dynamic array class. You will still need to be constantly re-allocating every time the array tries to grow beyond the current size. That is just the nature of C/C++.

- Robert

doumalc++
February 6th, 2003, 03:33 AM
char* pszDynArray = NULL;
unsigned int nSize = 30;
pszDynArray = new char[nSize];

Doesn't the above code suffers from the same problem if you input more than 30 char elements?

Further, it is weak as far as being dynamic.

I am currently working a better quick fix to all this till I learn better ways to handle such issues. I will post the code when I am done.

After the quick fix, I will see if I can create my own dynamic class.

PaulWendt
February 6th, 2003, 06:15 AM
There is no quick fix; the man was right about what he was
saying: when you don't specify a size, the array gets its size from
its initialization parameters. Also, arrays are stack-based and,
thus, cannot grow at runtime.

There's no need to write your own class for arrays; like others
have posted [and as you have acknowledged] there is an existing
class called std::vector that will do everything you need. If you
want different functionality, there's always list ... or deque.

--Paul

Philip Nicoletti
February 6th, 2003, 07:12 AM
As has been mentioned, for general dynamic arrays - vector.

For dynamc arrays of char - string.

Specifically for you example :


std::string inFile;
cin >> inFile;
fstream in(inFile.c_str());

doumalc++
February 6th, 2003, 08:01 AM
Originally posted by Philip Nicoletti
As has been mentioned, for general dynamic arrays - vector.

For dynamc arrays of char - string.

Specifically for you example :


std::string inFile;
cin >> inFile;
fstream in(inFile.c_str());


^gold!
Just what I needed (the conversion from string to char*).

Thanks to everyone. After reading your replies I now have a better understanding of the mechanism of arrays. Mainly, as PaulWendt said, arrays are stack-based and,
thus, cannot grow at runtime. In my implementation, I was actually trying to make the array grow at runtime as if it was a vector.

The term dynamic array led me to expect more functionality and implementation than possible.

update: I re-wrote the program using vectors and found that if works much better that way.

Graham
February 6th, 2003, 10:13 AM
To reiterate: the buffer-overflow problem is the main reason why you should avoid C-style arrays (whether on the stack or the heap) and use proper container classes that manage memory for you.

mwilliamson
February 6th, 2003, 06:55 PM
The key point about my method is that the size of the array is decided at run time, not at compile time. You could of course do some calculations to determine nSize and create whatever size you want. When copying to this dynamic array you should use safe, truncating copy functions like _snprintf or strncpy, not sprintf or strcpy (or memcpy for other types).

You method does not work. It is very bad programming. You are creating a single character and trying to use it as an array. You might as well write

char* s = 0x01234567;
cin>>s;

Both will work and in both cases you are writting memory you are not ment to modify.

And you are right, there are problems with this method and it can be difficult to use, which is why the vector template was created.

doumalc++
February 6th, 2003, 10:08 PM
Originally posted by mwilliamson
The key point about my method is that the size of the array is decided at run time, not at compile time. You could of course do some calculations to determine nSize and create whatever size you want.

//Edit: I got the picture. I went back and successful did the program using dynamic arrays and it worked.


Your method does not work. It is very bad programming. You are creating a single character and trying to use it as an array. You might as well write

char* s = 0x01234567;
cin>>s;

Both will work and in both cases you are writting memory you are not ment to modify.


Yep, I know. Just learning.


And you are right, there are problems with this method and it can be difficult to use, which is why the vector template was created.

Yeah, I am discovering that not everything I am learning is good use. Again the term "dynamic array" threw me off and let me to expect more. So, for now I am sticking to container class till I get a better hand at this.

Thanks for helping.

doumalc++
February 7th, 2003, 03:03 AM
#include <iostream>
#include <string>
#include <fstream>
#include <vector>

using namespace std;

typedef unsigned short int uShort;

int main()
{
vector<char> vCh;
char ch;
char *arrayCh;

cout<<"\nEnter the name of the file to read: \t";

while(cin.get(ch))
{
if(ch == '\n')
break;
vCh.push_back(ch);
}

const uShort size = vCh.size();

arrayCh = new char[size];

for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

cout<<"\n\n";
ifstream in(arrayCh);
string s;
while(getline(in, s))
cout<<s <<"\n";

delete[] arrayCh;
arrayCh =0;

return 0;
}


The above is a sample working code of what I was trying to do.
I know I could have used:

string inFile;
cin>>inFile;
ifstream in(inFile.c_str());

... but it does not work well with file name with space in it.

The first code on top still has 3 issues:
1. The first issue is with cin.get(), I have to use cin.ignore(integer, '\n') if the code is in the middle of other operations to clean up the prompt.
2. How do I determine the size of the array arrayCh points to? (programmatically)
3. How can I be sure that nothing is being overriden as the array grows? I mean, what is the real mechanism being all this?

doumalc++
February 7th, 2003, 11:25 AM
Ok, I know for a fact that the code is bad. I have found memory bugs in it.

There are problems if the file name is 1, 2, 4, 5, and 6 characters long - not 3 and above.

Trying to understand why.

Philip Nicoletti
February 7th, 2003, 11:51 AM
c-cstrings need to be NULL terminated :


arrayCh = new char[size+1];

for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

arrayCh[size] = 0;



#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main()
{
cout<<"\nEnter the name of the file to read: \t";

string inFile;
std::getline(cin,inFile);

ifstream in(inFile.c_str());

if (in) cout << in.rdbuf() << endl;

return 0;
}

doumalc++
February 7th, 2003, 03:16 PM
Thanks for the help.
I know your code works, but I have a need to solve the problem using dynamic arrays. My implementation of dynamic array in the above code is problematic at best. I am looking for someone to tell me why the code is shaddy.

And yes I forgot about "arrayCh = new char[size+1];", but the memory issues are still not solved.

Is the code below overriding memory it is not supposed to?

for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

mwilliamson
February 7th, 2003, 04:16 PM
Looking at this code:

const uShort size = vCh.size();
arrayCh = new char[size];
for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

For one, you should use your size variable in the loop. While vCh.size() is unlikely to change, if it did you would have a buffer overflow. Plus, there is no reason to calculate the size every iteration of the loop. Especially when you have it stored!

I don't see anything immediately wrong with the code, maybe you could tell me what you mean by memory errors.

doumalc++
February 7th, 2003, 05:38 PM
Originally posted by mwilliamson
Looking at this code:

const uShort size = vCh.size();
arrayCh = new char[size];
for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

For one, you should use your size variable in the loop. While vCh.size() is unlikely to change, if it did you would have a buffer overflow. Plus, there is no reason to calculate the size every iteration of the loop. Especially when you have it stored!

I don't see anything immediately wrong with the code, maybe you could tell me what you mean by memory errors.

I know about vCh.size() in the for loop. I did that to test something.

If you compile and run the code below, which is essentially the same code as the original and enter a file name that is 1, 2, 4, 5, and 6 character long, you will get an error. I have inserted a series of cout in order to determine the root of the problem. So, take a look at the output and you might see the root cause of the problem.


#include <iostream>
#include <string>
#include <fstream>
#include <vector>

using namespace std;

typedef unsigned short int uShort;

int main()
{
vector<char> vCh;
char ch;
char *arrayCh;

cout<<"\nEnter a choice: \t";

while(cin.get(ch))
{
if(ch == '\n')
break;
vCh.push_back(ch);
cout<<ch <<endl; //checking
}

const uShort size = vCh.size();
cout<<"size = " <<size <<endl; //checking
cout<<"size = " <<vCh.size() <<endl; //checking

arrayCh = new char[size + 1];

cout<<"arrayCh = " <<sizeof(arrayCh) <<"\tcontent: " <<arrayCh <<"\t\taddress: " <<&arrayCh <<endl;//checking
cout<<"arrayCh[] = " <<sizeof(arrayCh[size]) <<"\tcontent: " <<arrayCh[size] <<"\t\taddress: " <<&arrayCh[size] <<endl;

for(uShort i=0; i<(uShort)vCh.size()/*(size)checking*/; i++)
arrayCh[i] = vCh[i];

cout<<"arrayCh = " <<sizeof(arrayCh) <<"\tcontent: " <<arrayCh <<"\taddress: " <<&arrayCh <<endl;//checking
cout<<"arrayCh[] = " <<sizeof(arrayCh[size]) <<"\tcontent: " <<arrayCh[size] <<"\t\taddress: " <<&arrayCh[size] <<endl;

cout<<"\n\n";
ifstream in(arrayCh);
string s;
while(getline(in, s))
cout<<s <<"\n";

delete[] arrayCh;
arrayCh =0;

return 0;
}

doumalc++
February 7th, 2003, 05:53 PM
Here is the output when the file name is 2 characters (vc)


E:\>dynamic

Enter a choice: vc
v
c
size = 2
size = 2
arrayCh = 4 content: ─ĄC address: 1244660
arrayCh[] = 1 content: C address: C
arrayCh = 4 content: vcC address: 1244660
arrayCh[] = 1 content: C address: C



E:\>


As opposed to this when the file name is 3 characters long (cvc) or greater than 6 characters:


E:\>dynamic

Enter a choice: cvc
c
v
c
size = 3
size = 3
arrayCh = 4 content: ─ĄC address: 1244660
arrayCh[] = 1 content: address:
arrayCh = 4 content: cvc address: 1244660
arrayCh[] = 1 content: address:


-VC

1-2 vc
2-1 c
3-0
4-3 -vc
5-2 vc
6-1 c
7-0
8-0
9-0
10-0
11-0

E:\>

Philip Nicoletti
February 7th, 2003, 06:51 PM
you forgot to set the last character to NULL
as in my previous post :


arrayCh = new char[size+1];

for(uShort i=0; i<(uShort)vCh.size(); i++)
arrayCh[i] = vCh[i];

arrayCh[size] = 0; // you forgot this line


another way ... push NULL unto the vector array:


while(cin.get(ch))
{
if(ch == '\n')
break;
vCh.push_back(ch);
}

vCh.push_back(0); // add this line

const uShort size = vCh.size();

arrayCh = new char[size]; // no need for + 1

strcpy(arrayCh,&vCh[0]); // note the syntax of using the vector


even better, forget about the arrayCh completely :


while(cin.get(ch))
{
if(ch == '\n')
break;
vCh.push_back(ch);
}

vCh.push_back(0); // add this line

cout<<"\n\n";
ifstream in(&vCh[0]); // use the vector (again note syntax)

doumalc++
February 7th, 2003, 07:46 PM
code1: does not work still (corrected arrayCh[size + 1] = 0;)
code2: works well <= still worry about memory being overriden somewhere
code3: works well <= but I needed dynamic array implementation in the code.

Do you know any better way of getting inputs off the command prompt than cin.get() and getline()?

Thanks a bunch for the help. :)