I am writing a script which must copy some names into a multidimensional array, print the contents of the array and then deallocate the memory and terminate. The problem I am having is that when I run the script it only prints out the last name entered. Here is what I have done. Any help would be great! Thanks in advance!
#include <iostream>
#include <string.h>
using namespace std;
void createArray(int n);
void addDetail(char*& name, char*& surname);
void printArray();
void clear();
char ***details;
int used;
int size;
int main()
{
createArray(3);
char* tmpName = new char[20];
char* tmpSurName = new char[120];
strcpy(tmpName, "nameA");
strcpy(tmpSurName, "surnameA");
addDetail(tmpName,tmpSurName);
strcpy(tmpName, "nameB");
strcpy(tmpSurName, "surnameB");
addDetail(tmpName,tmpSurName);
strcpy(tmpName, "nameC");
strcpy(tmpSurName, "surnameC");
addDetail(tmpName,tmpSurName);
clear();
return 0;
}
void createArray(int n)
{
details= new char**[n];
for(int i=0; i<n; i++)
details[i] = new char*[2];
size = n;
used = 0;
}
void addDetail(char*& name, char*& surname)
{
if(occupation < size)
{
details[used][0] = name;
details[used][1] = surname;
used++;
}else{
cout << "Array Full " << endl;
}
}
void printArray()
{
for(int i=0; i<used; i++)
cout << details[i][0] << " " << details[i][1] << endl;
}
void clear()
{
for(int i=0; i<size; i++)
{
delete [] details[i];
details[i] = 0;
}
delete [] details;
details=0;
}
You didn't allocate memory for details[used][0] and details[used][1] so it's using whatever random address was in those locations.
Since this is C++ you can use string instead perhaps? std::string **details;. This should work with your existing code, except that it will leak memory.
Better still is to use a vector of vectors.
Something like:
std::vector<std::vector<std::string> > details;
Then the createArray function can go away completely and addDetail becomes simpler:
std::vector<string> newName;
newName.push_back(name);
newName.push_back(surname);
details.push_back(newName);
It is because each time, you are effectively storing the pointer tmpName and tmpSurName in the array details. Then in the next iteration, you overwrite the contents of the memory where tmpName and tmpSurName point to, so at the end you'll have a list that contains the last name/surname n times.
To solve it, you need to re-allocate tmpName and tmpSurName before each call to addDetail.
Btw, why do you need to use an (ewww) char***, and can't use e.g. the STL?
What it looks like is happening is that you are not adding the string to the array, you are adding a pointer to name and surname. Every instance is pointing at that variable, so when you ask the array what it contains it goes and asks name and surname, which will only contain the last value.
Also that array, are you sure its working how you want it to work? Arrays are... concrete things. Your essentially saying "I want 5 of these, they will be this big (based on the type you put in)" and the computer quietly goes "well I'll set aside space for those here and you can put them in when your ready". When your code puts those names in there, there really isn't any prep on where to store them. If you fill up that space and go beyond you go to bad places. So what you should do is have that last * of char*** be a pointer to a char[120] so that you know (for your purposes atleast) it never gets filled up. Do that in your createArray function after you have created the outer arrays.
You keep overwriting your temporary buffers rather than making new buffers for each entry in the array. As a result, only the last data written to the buffer survives.
Here's a rough guide on one way to fix it, though this sample may have some problems - I made no attempt to compile or test this.
This portion of main belongs in addDetail:
char* tmpName = new char[20];
char* tmpSurName = new char[120];
strcpy(tmpName, "nameA");
strcpy(tmpSurName, "surnameA");
So, your new addDetail would look something like:
void addDetail(char*& name, char*& surname)
{
if(occupation < size)
{
details[used][0] = new char[20];
details[used][1] = new char[120];
strcpy(details[used][0], name);
strcpy(details[used][1], surname);
used++;
}else{
cout << "Array Full " << endl;
}
}
And it would be called from main like:
addDetail("nameA", "surnameA");
You'd need to update clear to properly cleanup the allocations made in addDetail though.
Related
Here is the specification for the code:
You are to use the Word and Dictionary classes defined below and write all member functions and any necessary supporting functions to achieve the specified result.
The Word class should dynamically allocate memory for each word to be stored in the dictionary.
The Dictionary class should contain an array of pointers to Word. Memory for this array must be dynamically allocated. You will have to read the words in from the file. Since you do not know the "word" file size, you do not know how large to allocate the array of pointers. You are to let this grow dynamically as you read the file in. Start with an array size of 8, When that array is filled, double the array size, copy the original 8 words to the new array and continue.
You can assume the "word" file is sorted, so your Dictionary::find() function must contain a binary search algorithm. You might want to save this requirement for later - until you get the rest of your program running.
Make sure you store words in the dictionary as lower case and that you convert the input text to the same case - that way your Dictionary::find() function will successfully find "Four" even though it is stored as "four" in your Dictionary.
Here is my code so far.
#include <cstring>
#include <iostream>
#include <fstream>
using namespace std;
class Word
{
char* word_;
public:
Word(const char* text = 0);
~Word() { delete[] word_; word_ = nullptr; }
const char* word() const;
};
Word::Word(const char* arg)
: word_(new char[strlen(arg) + 1])
{
strcpy(word_, arg);
}
const char* Word::word() const
{
return word_;
}
class Dictionary
{
Word** words_;
unsigned int capacity_; // max number of words Dictionary can hold
unsigned int numberOfWordsInDictionary_;
void resize() {
capacity_ = capacity_ * 2;
cout << "Size = " << capacity_ << endl;
};
void addWordToDictionary(char* word) { words_ += *word; };
public:
Dictionary(const char* filename);
~Dictionary() {
delete[] words_; words_ = nullptr;
};
bool find(const char* word);
};
Dictionary::Dictionary(const char * filename)
: words_(new Word*[8]), capacity_(8), numberOfWordsInDictionary_(0)
{
ifstream fin(filename);
if (!filename) {
cout << "Failed to open file!" << endl;
}
char buffer[32];
while (fin.getline(buffer, sizeof(buffer)))
{
if (numberOfWordsInDictionary_ == capacity_)
{
resize();
}
addWordToDictionary(buffer);
}
}
bool Dictionary::find(const char * left)
{
int last = capacity_ - 1,
first = 0,
middle;
bool found = false;
while (!found && first <= last) {
middle = (first + last) / 2;
if (strcmp(left, reinterpret_cast<char*>(words_[middle])) == 0) {
found = true;
}
else if (left > reinterpret_cast<char*>(words_[middle]))
last = middle - 1;
else
first = middle + 1;
}
return found;
}
;
bool cleanupWord(char x[] ) {
bool lower = false;
int i = 0;
while (x[i]) {
char c = x[i];
putchar(tolower(c));
lower = true;
}
return lower;
}
int main()
{
char buffer[32];
Dictionary Websters("words.txt");
ifstream fin("gettysburg.txt");
cout << "\nSpell checking " << "gettysburg.text" << "\n\n";
while (fin >> buffer) {
if (cleanupWord(buffer) == true) {
if (!Websters.find(buffer)) {
cout << buffer << " not found in the Dictionary\n";
}
}
}
system("PAUSE");
}
When I run the program it stops after outputting "spellchecking Gettysburg.txt" and I don't know why. Thank you!
The most likely cause of this problem is the text files have not been opened. Add a check with is_open to make sure they have been opened.
When using Relative Paths (any path that does not go all the way back to the root of the file system (and is an Absolute Path)), take care that the program is being run from the directory you believe it to be. It is not always the same directory as the executable. Search Term to use to learn more about this: Working Directory.
Now on to other reasons this program will not work:
void addWordToDictionary(char* word) { words_ += *word; };
is not adding words to the dictionary. Instead it is advancing the address at which words_ points by the numeric value of the letter at *word. This is extremely destructive as it loses the pointer to the buffer allocated for words_ in the constructor making delete[] words_; in the Dictionary destructor ineffective and probably fatal.
Instead you want to (Note I use want to with a bit of trepidation. What you really want to do is use std::vector and std::string, but I strongly suspect this would upset the assignment's marker)
Dynamically allocate a new Word with new.
Place this word in a free spot in the words_ array. Something along the lines of words_[numberOfWordsInDictionary_] = myNewWord;
Increase numberOfWordsInDictionary_ by 1.
Note that the Words allocated with new must all be released in the Dictionary destructor. You will want a for loop to help with this.
In addition, I would move the
if (numberOfWordsInDictionary_ == capacity_)
{
resize();
}
from Dictionary to addWordToDictionary so that any time addWordToDictionary is called it is properly sized.
Hmmm. While we're at it, let's look at resize
void resize() {
capacity_ = capacity_ * 2;
cout << "Size = " << capacity_ << endl;
};
This increases the object's capacity_ but does nothing to allocate more storage for words_. This needs to be corrected. You must:
Double the value of capacity_. You already have this.
Allocate a larger buffer to hold the replacement of words_ with new.
Copy all of the Words in words_ to the larger buffer.
Free the buffer currently pointed to by words_
Point words_ at the new, larger buffer.
Addendum
I haven't looked closely at find because the carnage required to fix the reading and storage of the dictionary will most likely render find unusable even if it does currently work. The use of reinterpret_cast<char*> is an alarm bell, though. There should be no reason for a cast, let alone the most permissive of them all, in a find function. Rule of thumb: When you see a reinterpret_cast and you don't know what it's for, assume it's hiding a bug and approach it with caution and suspicion.
In addition to investigating the Rule of Three mentioned in the comments, look into the Rule of Five. This will allow you to make a much simpler, and probably more efficient, dictionary based around Word* words_, where words_ will point to an array of Word directly instead of pointers to Words.
I'm new to C++ and I am working on a function to shuffle strings
It takes an array of strings, shuffles them, and returns them back to the main.
I am returning a pointer to an array of strings called shuffled. The problem I have is that when I try to save that new pointer to the array to another pointer in the main, I start getting weird values that either reference to a file location in my computer or a bunch of numbers.
I'll post the entire code here but really what you want to look at is the return types, how I return it and how I save it in main. Please tell me why my pointer is not referencing the working array that is created in the function. Here's the code:
#include <cstdio>
#include <string>
#include <ctime>
#include <new>
#include <cstdlib>
using namespace std;
const char * getString(const char * theStrings[], unsigned int stringNum)
{
return theStrings[stringNum];
}
string * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
int randList[sz];
for(int p = 0; p < sz; p++)
{
randList[p] = sz;
}
srand(time(0));//seed randomizer to current time in seconds
bool ordered = true;
while(ordered)
{
int countNumberInRandList = 0;//avoid having a sz-1 member list length (weird error I was getting)
for(int i = 0; i < sz; i++)
{
int count = 0;
int randNum = rand()%(sz+1);//get random mod-based on size
for(int u = 0; u < sz; u++)
{
if(randList[u] != randNum)
{
count++;
}
}
if(count == sz)
{
randList[i] = randNum;
countNumberInRandList++;
}
else
i--;
}
//check to see if order is same
int count2 = 0;
for(int p = 0; p < sz; p++)
{
if(randList[p] == p)
{
count2++;
}
}
if(count2 < sz-(sz/2) && countNumberInRandList == sz)
{
ordered = false;
}
}
string * shuffled[sz];
for(int r = 0; r < sz; r++) //getting random num, and str list pointer from passed in stringlist and setting that value at shuffled [ random ].
{
int randVal = randList[r];
string * strListPointer = &theStrings[r];
shuffled[randVal] = strListPointer;
}
for(int i = 0; i < sz; i++)
{
printf("element %d is %s\n", i, shuffled[i]->c_str());//correct values in a random order.
}
return *shuffled;
}
int main()
{
string theSt[] = {"a", "b", "pocahontas","cashee","rawr", "okc", "mexican", "alfredo"};
string * shuff = shuffleStrings(theSt);//if looped, you will get wrong values
return 0;
}
Strings allocate their own memory, no need to give them the "length" like you would have to do for char arrays. There are several issues with your code - without going into the details, here are a few working/non-working examples that will hopefully help you:
using std::string;
// Returns a string by value
string s1() {
return "hello"; // This implicitly creates a std::string
}
// Also returns a string by value
string s2() {
string s = "how are you";
return s;
}
// Returns a pointer to a string - the caller is responsible for deleting
string* s3() {
string* s = new string;
*s = "this is a string";
return s;
}
// Does not work - do not use!
string* this_does_not_work() {
string s = "i am another string";
// Here we are returning a pointer to a locally allocated string.
// The string will be destroyed when this function returns, and the
// pointer will point at some random memory, not a string!
// Do not do this!
return &s;
}
int main() {
string v1 = s1();
// ...do things with v1...
string v2 = s2();
// ...do things with v2...
string* v3 = s3();
// ...do things with v3...
// We now own v3 and have to deallocate it!
delete v3;
}
There are a bunch of things wrong here -- don't panic, this is what happens to most people when they are first wrapping their brains around pointers and arrays in C and C++. But it means it's hard to put a finger on a single error and say "this is it". So I'll point out a few things.
(But advance warning: You ask about the pointer being returned to main, your code does indeed do something wrong with that, and I am about to say a bunch of things about what's wrong and how to do better. But that is not actually responsible for the errors you're seeing.)
So, in shuffleStrings you're making an array of pointers-to-string (string * shuffled[]). You're asking shuffleStrings to return a single pointer-to-string (string *). Can you see that these don't match?
In C and C++, you can't actually pass arrays around and return them from functions. The behaviour you get when you try tends to be confusing to newcomers. You'll need to understand it at some point, but for now I'll just say: you shouldn't actually be making shuffleStrings try to return an array.
There are two better approaches. The first is to use not an array but a vector, a container type that exists in C++ but not in C. You can pass arrays around by value, and they will get copied as required. If you made shuffleStrings return a vector<string*> (and made the other necessary changes in shuffleStrings and main to use vectors instead of arrays), that could work.
vector<string *> shuffleStrings(...) {
// ... (set things up) ...
vector<string *> shuffled(sz);
// ... (fill shuffled appropriately) ...
return shuffled;
}
But that is liable to be inefficient, because your program is then having to copy a load of stuff around. (It mightn't be so bad in this case, because a smallish array of pointers isn't very large and because C++ compilers are sometimes able to figure out what you're doing in cases like this and avoid the copying; the details aren't important right now.)
The other approach is to make the array not in shuffleStrings but in main; to pass a pointer to that array (or to its first element, which turns out to be kinda equivalent) into shuffleStrings; and to make shuffleStrings then modify the contents of the array.
void shuffleStrings(string * shuffled[], ...) {
// ... (set things up) ...
// ... (fill shuffled appropriately) ...
}
int main(...) {
// ...
string * shuffled[sz];
shuffleStrings(shuffled, theSt);
// output strings (main is probably a neater place for this
// than shuffleStrings)
}
Having said all this, the problems that are causing your symptoms lie elsewhere, inside shuffleStrings -- after all, main in your code never actually uses the pointer it gets back from shuffleStrings.
So what's actually wrong? I haven't figured out exactly what your shuffling code is trying to do, but that is where I bet the problem lies. You are making this array of pointers-to-string, and then you are filling in some of its elements -- the ones corresponding to numbers in randList. But if the numbers in randList don't cover the full range of valid indices in shuffled, you will leave some of those pointers uninitialized, and they might point absolutely anywhere, and then asking for their c_strs could give you all kinds of nonsense. I expect that's where the problem lies.
Your problem has nothing to do with any of the stuff you are saying. As you are a beginner I would suggest not presuming that your code is correct. Instead I would suggest removing parts that are not believed to be problematic until you have nothing left but the problem.
If you do this, you should quickly discover that you are writing to invalid memory.
part two : you can't seem to decide on the type of what you are returning. Are you building a pointer to an array to return or are you returning an array of pointers.... you seem to switch between these intermittently.
part three : read #Gareth's answer, he explains about passing parameters around nicely for your instance.
Can someone explain why this code does not work? It keeps crashing when it asks for input in addCar().
I think something is wrong with copying an array, but I can't figure out what exactly. I also tried to use copy() but it didn't work either.
#include <iostream>
#include <string>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct Car{
string Brand;
string model;
long mileage;
};
void addCar(int *ptr, struct Car *arra){
*ptr=*ptr+1;
Car *newArr = new Car[*ptr];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
cout<<"Brand ";
getline(cin,newArr[*ptr].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr].model);
cout<<"mileage ";
cin>>newArr[*ptr].mileage;
arra=newArr;
};
int main(int argc, char** argv) {
int size=1;
int *ptr_size;
ptr_size=&size;
Car *tab=new Car[*ptr_size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
addCar(*ptr_size, tab);
return 0;
}
The fail is probably here:
getline(cin,newArr[*ptr].Brand);
A bit above, you did this: *ptr=*ptr+1; and made newArr an array of *ptr elements. Arrays are origin zero. That means the first item in the array is newArr[0]. The last will be at newArr[*ptr-1], so writing into newArr[*ptr] is writing over someone else's memory. Generally a bad thing to do.
But this is also not cool:
*ptr=*ptr+1;
Car *newArr = new Car[size+1];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
You increment the size of the array. That's OK.
You create a new array with the new size. That's OK.
You copy new size number of elements from the old array to the new array and over shoot the end of the old array. Not OK.
The best answer is given by Jerry Coffin and Paul McKenzie in the comments: use a std::vector. If this is not allowed... Ick.
But alrighty then.
First, memcpy literally copies a block of memory. It does not know or care what that block of memory is or what it contains. Never use memcpy unless you are copying something really, really simple like basic data type or a structure made up of nothing but basic data types. String is not basic. The data represented by a string might not be inside the string. In that case, you copy a pointer to the string and that pointer will not be valid after the death of the string. That's not a problem in your case because you don't kill the string. That leads to problem 2. Let's fix that before you get there. The easiest way (other than vector) is going to be:
for (int index = 0; index < *ptr-1; index++)
{
newArr[index] = arra[index];
}
An optimization note. You don't want to resize and copy the array every time you add to it. Consider having two integers, one size of array and the other index into array and double the size of the array every time the index is about to catch up with the size.
When you allocate any memory for data with new somebody has to clean up and put that memory back with delete. In C++ that somebody is you. so, before you arra=newArr; you need to delete[] arra;
Passing in the array index as a pointer overcomplicates. Use a reference or just pass by value and return the new index. Also, don't name a variable ptr. Use something descriptive.
void addCar(int &arrasize, struct Car *arra){
or
int addCar(int arrasize, struct Car *arra){
Next problem: int addCar(int arrasize, struct Car *arra){ passes in a pointer to arra. But you passed the pointer by value, made a copy of the pointer, so when you change the pointer inside the function, it's only the copy that got changed and the new array is not going to come back out again. So,
int addCar(int arrasize, struct Car * & arra){
Passes in a reference to the pointer and allows you to modify the pointer inside the function.
Putting all that together:
int addCar(int size, struct Car * & arra)
{
Car *newArr = new Car[size + 1];
for (int index = 0; index < size; index++)
{
newArr[index] = arra[index];
}
cout << "Brand ";
getline(cin, newArr[size].Brand);
cout << "Model ";
getline(cin, newArr[size].model);
cout << "mileage ";
cin >> newArr[size].mileage;
delete[] arra;
arra = newArr;
return size+1;
}
int main()
{
int size=1;
Car *tab=new Car[size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
size = addCar(size, tab);
// do more stuff;
// bit of test code here
for (int index = 0; index < size; index++)
{
cout << "Car " << index << " brand =" <<tab[index].Brand << " Model=" << tab[index].model << " mileage=" <<tab[index].mileage << endl;
}
delete[] tab;
return 0;
}
When you are copying the old array to the new one you are accessing invalid memory, remember that, in that point, arra has size *ptr-1 not *ptr, so the line should be
memcpy(newArr, arra, (*ptr-1)*sizeof(Car));
also in the other lines you should insert the new value in the *ptr-1 position because the indexes in newArr go from 0 to size-1 ie *ptr-1:
cout<<"Brand ";
getline(cin,newArr[*ptr-1].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr-1].model);
cout<<"mileage ";
cin>>newArr[*ptr-1].mileage;
I have a function whose signature is as follows:
GetCustomers( wchar_t** Name,int *count);
In main method: Call to customer looks like this:
GetCustomers( Name,&count);
The body of the function is as follows: (since count of customers is unknown , I am trying to allocate meomry dynamically)
GetCustomers( wchar_t** Name,int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
Names = new wchar_t*[myCustomersCount];
for (int i=0; i < myCustomersCount; i++ )
{
Names[i] = new wchar_t;
}
//Logic to get customer names in wchar_t* strName = "Name1";
Names[0] = strName;
*count = myCustomersCount;
}
I would think that this implementation would allow array Name to be passed back correctly to the Main() function with memory allocation on heap but it seems not to work. What is wrong here? myCustomersCount seems to be correct in caller.
PS: The code compile and executes but array received in Main is garbage.
You seem to be thinking in terms of C, not really C++. I'd use something like:
std::vector<std::string> GetCustomers();
or (probably preferred):
template <class outIt>
void GetCustomers(outIt output_iterator);
The latter you'd use something like:
std::vector<std::wstring> customers;
GetCustomers(std::back_inserter(customers));
The third obvious possibility would be to just equip your customers class with a begin() and end() member functions that return iterators to the customers data.
Edit2: Here's some tested demo code:
#include <stdio.h>
#include <string.h>
#include <wchar.h>
void GetCustomers(wchar_t ***names, int *count) {
static wchar_t *myCustomers[] = {
L"You",
L"Him",
L"Her"
};
int myCustomersCount = 3;
wchar_t **temp = new wchar_t *[myCustomersCount];
*count = myCustomersCount;
for (int i=0; i<myCustomersCount; i++) {
temp[i] = new wchar_t[wcslen(myCustomers[i])+1];
wcscpy(temp[i], myCustomers[i]);
}
*names = temp;
}
int main() {
wchar_t **customers;
int count;
GetCustomers(&customers, &count);
for (int i=0; i<count; i++)
printf("%S\n", customers[i]);
return 0;
}
I'm really not sure what you're trying to do here; from what I understand about your code; you're trying to store some strings into an array of an array of character pointers.
GetCustomers(wchar_t **Name, int *count) {
Name = new wchar_t*[myCustomersCount];
for(int i = 0; i < myCustomersCount; i++) {
/* Get your customer name and store into strName */
Name[i] = strName;
}
*count = myCustomersCount;
}
In main, presumably you've got something like this
wchar_t *Name = NULL;
and then you say
GetCustomers( Name,&count);
This passes Name by value, but you want to pass it by reference:
GetCustomers( &Name,&count);
And presumably it's just a typo, but your parameter name is Name (singular) but you refer to it as Names (plural) in the function:
GetCustomers( wchar_t** Name,int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
Names = new wchar_t*[myCustomersCount];
In any case, you want to assign to where Name is pointing, not to itself:
*Names = new wchar_t*[myCustomersCount];
Then for each element in Names you allocate one character, but then overwrite the first one with strName. The allocation is unnecessary (and in fact is a memory leak), and you should assign from strName to each element within the loop, as Suroot's answer does.
2 definite issue and 1 potential issue with your code. The main issue causing your problem first: Name itself is passed by value. That means when you you assign to it in the very first line of your function when you new the memory, you're assigning to the copy, not the original! You have three options: 1) keep the double pointer, make the caller responsible for allocating the memory, and add a third parameter for number of names that the array can hold (recommended) or 2) make Name a triple pointer (wchar_t*** Name) and then you can assign to it by dereferencing it: *Name = new wchar_t*[myCustomersCount]; or 3) just return the wchar_t** since you don't use the passed value for anything.
Then another definite issue: when you allocate memory for each name, you need to use the new[] operator there as well because otherwise you're only allocating room for a single wchar_t.
Finally, the potential issue. You don't show how exactly this code is getting each customer name. But if strName points to memory that is getting reused for each customer name as you put them all in your array, you're going to have to wstrcpy each name into the array. If it doesn't, then you don't need to allocate memory for each Names[i] as you can just store the result right into Names[i].
A final note: just from looking at this code it seems like you're going to have lots of problems with memory management as it seems very unclear who is responsible for allocating and deallocating memory which is likely going to lead to memory leaks. Try your best to keep the responsibility for allocating and deallocating the memory in the same location and you'll reduce lots of potential headaches -- have callers allocate the memory before they call the function and have the caller deallocate the memory when they're done with it.
/* changed */
wchar_t** GetCustomers( int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
wchar_t **Names = new wchar_t*[myCustomersCount];
for (int i=0; i < myCustomersCount; i++ )
{
/* changed */
Names[i] = new wchar_t[MAX_NAME_SIZE];
}
//Logic to get customer names in wchar_t* strName = "Name1";
Names[0] = strName; /* possible wstrcpy needed here? */
*count = myCustomersCount;
/* changed */
return Names;
}
Edit
If you really absolutely can't change the function signature, the only solution I can think of is to flatten your array and use C memory functions (you could also just use a long series of news and deletes, but why not use realloc when this is what it's made for and you're managing memory without using other C++ features like the STL anyways?):
GetCustomers( wchar_t **Names, int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
size_t names_size = 0;
for (int i=0; i < myCustomersCount; i++ )
{
strName = ???; // whatever you use to get the next name
size_t old_names_size = names_size;
names_size += (wstrlen(strName) + 1) * sizeof(wchar_t); //+1 for NULL
*Names = realloc(*Names, names_size);
if (!*Names) {
// Memory allocation failed, log it, abort, do whatever
}
wstrcpy(Names[old_names_size], strName);
}
*count = myCustomersCount;
}
Note that this assumes that Name has already been initialized and points to memory where you can store a wchar_t*, just like the original version assumed count has been initialized and points to memory where you can store an int.
I thought I'd make a fresh start in a new answer.
Here's a simple program that does what I think you're trying to do, with the constraint that the signature of GetCustomers must not be altered.
void GetCustomers(wchar_t** Names,int *count)
{
// Allocate the array of names
wchar_t **ar = new wchar_t*[3];
// Allocate space for each name in the array
ar[0] = new wchar_t[10];
ar[1] = new wchar_t[10];
ar[2] = new wchar_t[10];
// Fill in the names
wcscpy(ar[0],L"joe");
wcscpy(ar[1],L"jim");
wcscpy(ar[2],L"bob");
// Return the array through the bad GetCustomers signature
*Names = (wchar_t*)ar;
*count = 3;
}
int wmain(int argc, wchar_t* argv[])
{
// names is an array of strings
wchar_t **names = NULL;
int count;
// Squeeze names into the dodgy GetCustomers signature
GetCustomers((wchar_t**)&names,&count);
// Delete each name
for(size_t x = 0; x < count; ++x)
delete[] names[x];
// Delete the array
delete[] names;
return 0;
}
Note that I've matched the cast inside the function with another one in main. This way we keep everything as it should be, except for that pesky GetCustomers signature.
Does this help?
I have started out to write a simple console Yahtzee game for practice. I just have a question regarding whether or not this function will leak memory. The roll function is called every time the dices need to be re-rolled.
What it does is to create a dynamic array. First time it is used it will store 5 random values. For the next run it will only re-roll all except for the dice you want to keep. I have another function for that, but since it isn't relevant for this question I left it out
Main function
int *kast = NULL; //rolled dice
int *keep_dice = NULL; //which dice to re-roll or keep
kast = roll(kast, keep_dice);
delete[] kast;
and here's the function
int *roll(int *dice, int *keep) {
srand((unsigned)time(0));
int *arr = new int[DICE];
if(!dice)
{
for(int i=0;i<DICE;i++)
{
arr[i] = (rand()%6)+1;
cout << arr[i] << " ";
}
}
else
{
for(int i=0;i<DICE;i++)
{
if(!keep[i])
{
dice[i] = (rand()%6)+1;
cout << "Change ";
}
else
{
keep[i] = 0;
cout << "Keep ";
}
}
cout << endl;
delete[] arr;
arr = NULL;
arr = dice;
}
return arr;
}
Yes, it can leak. Just for example, using cout can throw an exception, and if it does, your delete will never be called.
Instead of allocating a dynamic array yourself, you might want to consider returning an std::vector. Better still, turn your function into a proper algorithm, that takes an iterator (in this case, a back_insert_iterator) and writes its output there.
Edit: Looking at it more carefully, I feel obliged to point out that I really dislike the basic structure of this code completely. You have one function that's really doing two different kinds of things. You also have a pair of arrays that you're depending on addressing in parallel. I'd restructure it into two separate functions, a roll and a re_roll. I'd restructure the data as an array of structs:
struct die_roll {
int value;
bool keep;
die_roll() : value(0), keep(true) {}
};
To do an initial roll, you pass a vector (or array, if you truly insist) of these to the roll function, which fills in initial values. To do a re-roll, you pass the vector to re-roll which re-rolls to get a new value for any die_roll whose keep member has been set to false.
Use a (stack-allocated) std::vector instead of the array, and pass a reference to it to the function. That way, you'll be sure it doesn't leak.
The way you allocate memory is confusing: memory allocated inside the function must be freed by code outside the function.
Why not rewrite it something like this:
int *kast = new int[DICE]; //rolled dice
bool *keep_dice = new bool[DICE]; //which dice to re-roll or keep
for (int i = 0; i < DICE; ++i)
keep_dice[i] = false;
roll(kast, keep_dice);
delete[] kast;
delete[] keep_dice;
This matches your news and deletes up nicely. As to the function: because we set keep_dice all to false, neither argument is ever NULL, and it always modifies dice instead of returning a new array, it simplifies to:
void roll(int *dice, int *keep) {
for(int i=0;i<DICE;i++)
{
if(keep[i])
{
keep[i] = false;
cout << "Keep ";
}
else
{
dice[i] = (rand()%6)+1;
cout << "Change ";
}
}
cout << endl;
}
Also, you should move the srand call to the start of your program. Re-seeding is extremely bad for randomness.
My suggestion would be to take time out to buy/borrow and read Scott Meyers Effective C++ 3rd Edition. You will save yourselves months of pain in ramping up to become a productive C++ programmer. And I speak from personal, bitter experience.