How can I use a search function on a dynamic array? - c++

I'm trying to use a linear search function on a dynamic array I created but then the teaching assistant for my computer science class told us that most search functions use const arrays.
Is there any way I can edit my dynamic array to become contant? Or is it also possible to make a search function that uses a dynamic array (and would not give errors?).
I'll give a brief insight into my code:
I dynamically create an array using the rows I read in from a file and then dynamically allocate each row to an array of columns.
char ** domain[] = new char * [rows];
for(int i = 0; i < rows; i++)
{
*domain = new char[columns];
domain++;
}
The type of function that we were taught for searching is:``
char searchArray( const char list[], char letter, int maxSize)
{
>code goes here
}
Is there any other method of using a search function that takes in dynamic multidimensional arrays?
In response to the comments, I can't use vectors. This is an assignment for us to use normal arrays. I haven't been taught how to to use vectors yet.

In the line
char ** domain[] = new char * [rows];
char ** domain[] tries to make an array of char **. If the compiler didn't complain about not having a valid array size in the [] and you would have a 3D structure. You want just plain old char ** for a 2D structure, so
char ** domain = new char * [rows];
The loop filling out the inner dimension is correct except it loses track of the starting point of domain
for(int i = 0; i < rows; i++)
{
*domain = new char[columns];
domain++;
}
Should be something like
char ** temp = domain;
for(int i = 0; i < rows; i++)
{
*temp = new char[columns];
temp++;
}
To preserve the starting point, but for this case array notation is probably the smarter and easier-to-read option.
for(int i = 0; i < rows; i++)
{
domain[i] = new char[columns];
}
On to searchArray. It needs to know it's getting two dimensions, (const char **) and that there are two max sizes (maxRow and maxColumn). It will look something like
char searchArray(const char ** list,
char letter,
int maxRow,
int maxColumn)
{
>code goes here
}
Code goes here is your problem, but will probably be two nested for loops iterating to maxRow and maxColumn and returning when letter is found.
But... Why return a char? Returning the location in the array is much more useful. We could use std::pair, but if std::vector is off limits, pair probably is as well. Consider something like the following instead:
struct coord
{
int row;
int column;
};
coord searchArray(const char ** list,
char letter,
int maxRow,
int maxColumn)
{
coord location;
>code goes here
return location;
}
If the item is not found, set row and column to something impossible to get like -1 so you can easily test for the not found case.
Stop here unless you want to <expletive deleted> with your teacher's brain.
The above doesn't build a 2D array. You can't get a dynamically allocated 2D array in C++. What you have is an array of arrays. There are a couple downsides to this, look at all the work that goes into stitching one together and computers love it when things go in straight lines. Array of arrays doesn't. Every different allocation can be somewhere completely different in memory forcing the program to hop around, waiting on and loading different chunks of memory. Sometimes The program will spend more time sitting around waiting for stuff to be found and loaded than it'll spend doing the actual work. This sucks.
The solution is to make a 1D array and make it look like a 2D array. Here's an example of that from the C++ FAQ
You'll learn a lot of neat stuff from following this example, not the least of which being RAII and the Rule of Three, two concepts without which you cannot write non-trivial high quality C++ code.

Related

Dynamic 2D array of strings where the second dimension can change

So I have to make a 2-d array of strings named history[][], where history[i] stores all of the subjects currently involved in experiment i, and history[i][j] contains a string listing all of the experiments that this particular subject has been a part of. The thing is, I have to use int* numsubjects, an array of integers that tells me how many subjects are in experiment i. However, the contents of numsubjects should be able to move around as subjects can be moved into other experiments. I have no idea how to go about doing this. I cannot use vector, dequeue, or list.
experiments = 0;
numsubjects = new int[experiments+1];
numsubjects[experiments] = n;
history = new string*[0];
for(int j = 0; j < n; j++) {
history[0] = new string[j];
history[0][j] = "0";
}
The above code initializes everything when there is only one experiment, experiment 0. I need a way to make history somehow with numsubjects in it.
If you must use C-style arrays, then realloc() will allow you to resize your array.
However, since this is C++, I strongly encourage you to use std::vector or std::map.

Read amount of lines from a text file and store them as a constant int for array size c++

I'm new to C++ and having some problems. Basically what I have to do is read different kinds of text files and use the amount of lines as the size for the rows of a 2-dimensional array.
The input file looks like this:
int_n1 int_n2 (These are 2 integers needed later on for processing)
(blank line)
[amount of nurses][140] (too much to type out)
link to what it actually looks like here
http://puu.sh/lEh2y/e4f740d30f.png
My code looks like this:
//maak inputStream klaar voor gebruik
ifstream prefFile(INPUTPREF);
//test of de inputstream kan geopend worden
if (prefFile.is_open())
{
// new lines will be skipped unless we stop it from happening:
prefFile.unsetf(std::ios_base::skipws);
// count the newlines with an algorithm specialized for counting:
unsigned line_count = std::count(std::istream_iterator<char>(prefFile),std::istream_iterator<char>(),'\n');
int aantNurse = line_count + 1 - 2;
int nursePref[aantNurse][140];
}
Of course, just putting 'const' in front of 'int aantNurse' doesn't work.
Does anybody have a suggestion on how to solve this? I'd prefer not to have to use an oversized array that could fit everything, although that could be a possiblity.
As one of the possible solutions you can allocate memory for your array nursePref dynamically and release it in the end.
Just something like this:
int** nursePref = new int*[aantNurse];
for (int i = 0; i < aantNurse; ++i) {
nursePref[i] = new int[140];
}
Then release it properly using delete[]:
for (int i = 0; i < aantNurse; ++i) {
delete[] nursePref[i];
}
delete[] nursePref;
Also, as it's said already, using vectors is a better idea:
std::vector<std::vector<int> > nursePref(aantNurse, std::vector<int>(140));

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness

Is it possible to pass char[][] to a function requesting char**?

I am trying to call a function that takes char** as a parameter. Its job is to fill an array of strings (i.e. an array of char*). I know the max length of the strings, and I can pass the max number to fill as another parameter, so I was hoping to stack allocate it like this:
fill_my_strings(char** arr_str, int max_str); // function prototype
char fill_these[max_strings][max_chars_per_string]; // allocating chars
fill_my_strings(fill_these, max_strings); // please fill them!
Of course, I get the "cannot convert char[max_strings][max_chars_per_string] to char**" error.
I know this is some subtle (or not-so-subtle) problem with my understanding of the difference between arrays and pointers. I'm just not sure why it's not possible to pass this block of memory to something wanting a char** and have it fill in my stack-allocated chars. Could somebody please explain if this is possible, or if not, why not?
Is it possible to call a function like this without calling malloc / new?
The simple answer to your question is no; a two dimensional array is different than a pointer-to pointer type. Arrays decay to pointers to their first element, but pointers actually are that value.
The difference between these types is clear, if you cast both to char*
int x;
char *arr_pp[] = {"foo", "bar", "baz"};
char arr_2d[][4] = {"foo", "bar", "baz"};
char *cp = (char*)arr_pp;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
cp = (char*)arr_2d;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
The output (on my computer) is:
-80 -123 4
102 111 111
Where the first row is gibberish formed by the fact that I'm printing an address cast into bytes, and the second row is the ascii values of "foo".
In a function taking a char ** the compiler can't know to decay array types, which don't actually contain pointers.
Suppose you have n pointers to strings of m-1 maximum characters (m characters including the NULL).
So, in pure C:
sizeof(char[n][m]) will return n*m.
sizeof(char**) will return the size of a pointer in your architecture, probably 32 (if x86) or 64 (if x86_64).
char[n][m] actually allocates the n*m byte contiguously. char** allocates a single pointer. This pointer references a memory stripe of *n bytes. Each of these n pointers points to a memory stripe of m characters.
So, considering that sizeof(char) == u, if you declare char a[n][m], when you use a[i][j], the compiler understands *(a + i*m*u + j*u).
So, considering that sizeof(char *) == w, if you declare char **a, when you use a[i][j], the compiler understands ((a + i*w) + j*w).
Completely different data management.
The closes thing you could do to handle your special case is to create a char** variable, and populate it with the addresses of your stack allocated matrix.
char **tmp = malloc(max_strings * sizeof(char *));
int i;
for(i = 0; i < max_strings; i++){
tmp[i] = &(fill_these[i][0]); //you probably can't reference a char[][] with a single index - not confirmed
}
I am not sure why fill_my_strings() need a char** parameter. From your example, caller have already allocated the memory from stack. So using a char* should be OK.
But if you want to use char** or you can't modify the fill_my_strings() function, try following example code:
void fill_my_strings(char** arr_str, int max_chars_per_string, int max_strings)
{
for(int i = 0; i < max_strings; ++i)
{
//Make sure you have enough space
memcpy(*arr_str, "ABCD", sizeof("ABCD"));
*arr_str += max_chars_per_string;
}
}
char fill_these[max_strings][max_chars_per_string];
char* pointer = (char*)fill_these;
fill_my_strings(&pointer, max_strings, max_chars_per_string);
The obvious thing to do is build an index
In c use something like:
char string_list[num_strings][str_length];
// ...
char**index = calloc( (num_strings+1), sizeof(*index) ); // calloc insures NULL termination
for (int i=0; i<num_strings; ++i) {
index[i] = string_list[i]
}
In c++ prefer new[] to calloc;

Typecasting an array of structs (of pointers?) to be sent through winsock

I'm still getting my head around pointers and the like, so here goes...
Each client sends the position of the player correctly to the server.
On the server the data is then put into an array of structs (or points to structs?). The data of that array has also been verified to be correct.
The server then is meant to send all the data in that array back to each of the players
I would like to be able to send arrays from the server to the client (and back again) as the it is that approach I want to take in my head that I understand sort of (or arrays of pointers to structs?) eg, arrays of bullets and shooting, or other things.
I'm not worried about bandwidth at the moment or optimal code, that comes later when I understand it all better :)
Basically I've created a struct for my player:-
struct PlayerShip
{
unsigned int health;
unsigned int X;
unsigned int Y;
};
Then I've created an array (from the guidance of friends) that allows me to access the data of those structs (and typecast them as needed) (I think)
PlayerShip *playerArray[serverMaxClients];
for (int i = 0; i < serverMaxClients; i++)
{
playerArray[i] = new PlayerShip;
ZeroMemory(playerArray[i],sizeof(PlayerShip));
}
I recv data from all the connected players and feed it into the array
for (int slotIndex = 0; slotIndex < serverMaxClients; slotIndex++)
{
char szIncoming[1500];
ZeroMemory(szIncoming,1500);
int connectionStatus = recv(clientSocketArray[slotIndex], (char*)szIncoming,sizeof(szIncoming),0);
playerDataTemp = (PlayerShip*)szIncoming;
playerArray[slotIndex]->X = playerDataTemp->X;
playerArray[slotIndex]->Y = playerDataTemp->Y;
}
I print out the array and all the data is correct.
So the next step is to send that data back to the client.
I tried the following and a few variations of it, but I either get compile errors as I try to change variables into references and/or pointers (I still haven't had that epiphany moment where pointers and references suddenly makes sense), or the value comes out incorrectly. (the below case currently outputs an incorrect value)
for (int i = 0; i < serverMaxClients; i++)
{
char* outgoing = (char*)playerArray;
if (clientSlotTaken[i] == true)
{
send(clientSocketArray[i],outgoing,sizeof(playerArray),0);
}
int *valueCheck;
valueCheck = (int*)outgoing;
cout << "VALUE CHECK " << valueCheck << "\n";
delete outgoing;
}
The "Value Check" I'm expecting to be "100" as that should be player 1's health of 100 that was sent to the server earlier.
UPDATE
Okie now I'm starting to get my head around it a bit more.
playerArray is an array of pointers to structs. So I don't want to send the raw data from the array to the clients. I want to send the data of the structs to the players.
So I'm guessing I have to have a bit of code that creates a char array, which I populate with the data from all the player structs.
I tried the following but...
char outgoing[120];
PlayerShip *dataPopulator;
dataPopulator = &outgoing[0]; //Start at the begining of the array
for (int i=0; i < serverMaxClients; i++)
{
*dataPopulator = playerArray[i];
dataPopulator++;
}
I get the following errors
cannot convert 'char*' to 'PlayerShip*' in assignment|
no match for 'operator=' in '* dataPopulator = playerArray[i]'|
Thanks to Joriki, that help me understand it a bit more, but I still have a way to go :\ Still reading through lots of web pages that try to explain pointers and such
PlayerShip *playerArray[serverMaxClients];
declares an array of serverMaxClients pointers, each of which points to a PlayerShip structure.
Here
char* outgoing = (char*)playerArray;
you're referring to the address of this array of pointers, so your call to send will send a bunch of pointers, which is almost certainly not what you want. Also, here
delete outgoing;
you're trying to delete this array of pointers, which was allocated on the stack and not from the heap, so this might cause major problems; also, you're deleting the same pointer in every iteration.
I think the following comes closer to what you're intending to do:
for (int i = 0; i < serverMaxClients; i++)
{
char* outgoing = (char*)playerArray [i];
if (clientSlotTaken[i] == true)
{
send(clientSocketArray[i],outgoing,sizeof(PlayerShip),0);
}
int *valueCheck;
valueCheck = (int*)outgoing;
cout << "VALUE CHECK " << *valueCheck << "\n";
delete outgoing;
}
This sends the data in the PlayerShip structures, as opposed to just machine-dependent pointers to it, and it frees the memory allocated on the heap by "new PlayerShip", as opposed to the array of pointers to it allocated on the stack. Note also the added asterisk in the output statement for the value check; you were outputting a pointer instead of the value being pointed to. (Even if you'd added the asterisk, you would have just gotten an int cast of the first pointer in the array, rather than the health value in the PlayerShip structure it points to.)
I hope that helps; feel free to ask further questions in the comments if I haven't made it clear.
Update in response to ChiggenWingz' comments and udpate:
If you want to send all the data to each client, I see three options:
1) You can replace the send in my code with a loop:
if (clientSlotTaken[i] == true)
{
for (int j = 0;j < serverMaxClients;j++)
send(clientSocketArray[i],(char*)playerArray [j],sizeof(PlayerShip),0);
}
But I assume you're trying to avoid that since it may make the I/O less efficient.
2) You can do what you tried to do in your update. To resolve the errors you listed and make it work:
a) You need to cast the char* to a PlayerShip*, just like you had to cast the other way around in your earlier code.
b) In the copy assignment, you have a PlayerShip on the left, but a PlayerShip* on the right -- you need to dereference that pointer.
c) Using a fixed length like 120 is pretty dangerous; if you have more clients later, this could overflow; the size should be serverMaxClients * sizeof (PlayerShip).
d) "&outgoing[0]" is synonymous with "outgoing".
Putting that all together:
char outgoing[serverMaxClients * sizeof (PlayerShip)];
PlayerShip *dataPopulator;
dataPopulator = (PlayerShip*) outgoing; //Start at the begining of the array
for (int i=0; i < serverMaxClients; i++)
{
*dataPopulator = *playerArray[i];
dataPopulator++;
}
3) The best option I think would be to allocate all the PlayerShips together in one contiguous array instead of separately. You could do that either on the stack or on the heap, as you prefer:
a) On the heap:
PlayerShip *playerShips = new PlayerShip [serverMaxClients];
ZeroMemory (playerShips,serverMaxClients * sizeof(PlayerShip));
b) On the stack:
PlayerShip playerShips [serverMaxClients];
ZeroMemory (playerShips,sizeof(playerShips));
(The ZeroMemory call in a) would also work in b), but not the other way around.)
Now, independent of how you allocated the contiguous array, you can write the entire data to each client like this:
for (int i = 0; i < serverMaxClients; i++)
if (clientSlotTaken[i] == true)
send(clientSocketArray[i],(char *) playerShips,serverMaxClients * sizeof(PlayerShip),0);
(Again, in case b) you could replace the size calculation by sizeof(playerShips).
I hope that clarifies things further -- but feel free to ask more general questions about pointers if you're still confused :-)