Question:
How to make an array that has no limit - C++?
?
2013-11-23 13:24:08 UTC
I have created a very simple encryption algorithm. My current algorithm fetches the contents of a file and saves them to an array.

class Encrypter
{
public:
struct AppData{
char data[5];
}; AppData ds;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void GetFile(){
ifstream f("File.txt");
while (f >> ds.data[0] >> ds.data[1] >> ds.data[2] >> ds.data[3] >> ds.data[4]){
f >> ds.data[0] >> ds.data[1] >> ds.data[2] >> ds.data[3] >> ds.data[4];
}
Encrypt();
}
void Encrypt(){
if (ds.data[0] == 'h'){
ds.data[0] = 'm';
}
if (ds.data[1] == 'e'){
ds.data[1] = 'j';
}
if (ds.data[2] == 'l'){
ds.data[2] = 'q';
}
if (ds.data[3] == 'l'){
ds.data[3] = 'q';
}
if (ds.data[4] == 'o'){
ds.data[4] = 't';
}
CreateFile();
}
void CreateFile(){
ofstream nf("NewFile.txt");
nf << ds.data[0] << ds.data[1] << ds.data[2] << ds.data[3] << ds.data[4];
CloseP();
}
void CloseP(){
exit(0);
}
};

Do you see what's wrong? The array has to be told how many characters are in the file. How could I make it so that the program would just read the whole file and save each character to the array without me having to set the amount of characters that the array can hold? Also once this problem is solved, can I access each character in the array as shown above?
Four answers:
2013-11-23 13:32:43 UTC
You cannot make an array of infinite length...this is illogicial as you don't have infinite memory available. Your system would crash at worse case and at best your application would crash. To know how big to make the array, I would get the size of the file at the beginning. I recommend looking at the following ways which should always work as stat is part of the c runtime library on Windows, Mac and Linux.



long GetFileSize(std::string filename)

{

struct stat stat_buf;

int rc = stat(filename.c_str(), &stat_buf);

return rc == 0 ? stat_buf.st_size : -1;

}



or



long FdGetFileSize(int fd)

{

struct stat stat_buf;

int rc = fstat(fd, &stat_buf);

return rc == 0 ? stat_buf.st_size : -1;

}



On some systems there is also a stat64/fstat64. So if you need this for very large files you may want to look at using those.



EDIT: fstat is a c system call used to get information about files based on its file descriptor. So basically what my method is doing is saying is: From the file descriptor I pass to you, find me the size of this file described by this descriptor. stat is the struct that holds this information about the file, as well as other information (like permissions the file has). And as a check for failure, I look to make sure the return value is ok for fstat (like most c methods, it returns a negative value on failure) if it returns 0, your file is good and the value can be used and returned for processing by your program. Sorry for the long winded reply. And sorry for the late response, didn't see the additional detail until just now.
Jonathan
2013-11-23 23:53:58 UTC
C++ doesn't have a separate way of performing a realloc() call, using its "new" allocator. But C++ does support the older C methods using malloc/free and that system does, of course, support realloc().



If you are NOT reading up numbers and strings and the like, but are just reading up chars, then you could do as Tensai suggests and use a POSIX function like fstat(). Unfortunately, it isn't in the standards. So you cannot always count on it.



You can open the file in binary mode, seek to the end of the file, get the seek position, and if you assume that it means what it probably means (it's an assumption, of course, but often right) then you could use that as another way of estimating.



Finally, if you just want to use a very reliable method, you could do something like what is below. It uses C++ I/O. But since you have to use the C malloc system to get access to the realloc() function in C++, it also requires the cstdlib include file. The code here starts out assuming a small file, but doubles its allocations every time the current allocation is exceeded, so it grows geometrically. Also, if it runs into limitations using that mode (memory is getting very tight for some reason), it switches over to a add-by-bits mode where it creaps up on the absolute memory limits as it continues to read up the file. It's pretty robust. Of course, it cannot give you memory when there isn't enough for the file. For that, you'd need to switch to a file caching system if you really need something like that.



#include

#include

using namespace std;

char * readfile( istream &f ) {

    int c;

    char *result, *b;

    size_t maxn, extend, cn;

    enum { greedy, miserly } mode= greedy;

        if ( f == 0 ) return 0;

        result= (char *) malloc( maxn= extend= 1000U );

        if ( result == 0 ) return 0;

        for ( cn= 0, c= f.get(); c != EOF; c= f.get() ) {

            while ( cn >= maxn && extend > 0 ) {

                b= (char *) realloc( result, maxn + extend );

                if ( b != 0 ) {

                    result= b;

                    maxn += extend;

                    if ( mode == greedy ) extend= maxn;

                    break;

                }

                mode= miserly;

                extend >>= 1;

            }

            if ( cn >= maxn && !extend ) {

                free( result );

                return 0;

            }

            result[cn++]= c;

        }

        result[cn++]= '\0';

    return (char *) realloc( result, cn );

}



There are still other ways. But a lot depends on exactly how your encryption eventually works. (I can see your simple example, but I don't assume that is where you are going.) If it uses fixed block sizes, you have many more options that could easily support petabyte files without problems. But if your algorithms require random access at random locations, then a lot of those ideas stop working so well. I've not mentioned any of these ideas here, though. No idea if you care.



EDIT: To SKH... Using a linked list for a 'char' would not make much sense. You could do it. But it's an unbelievably excessive waste of memory and cpu time and I would LOVE to see the encryption algorithm working on that structure!!
J.J.'s Advice / Avis de J.J.
2013-11-23 22:14:13 UTC
If you need to create arrays that are allocated dynamically (i.e. you don't know the exact length that will be needed when you're writing the program), then you have to either create them as pointers on the heap, or use vectors.



Using the heap:

int n;

cout << "How many items are there?"

cin >> n;

int* x = new int[n];



Using vectors:

#include

...

vector x; // Defined with "vector varname;". Initial size is 0.

x.push_back(7);

x.push_back(10); // This expands vector (x) by one and inserts a value of 10.

for(int i=0; i
// Output: 710
SKH
2013-11-24 00:24:54 UTC
Try using a linked list instead of an array: http://www.cprogramming.com/tutorial/lesson15.html



You can then allocate memory as needed, and do checks to see if the system has enough available on the go, and gracefully handle errors if it's not.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...