Having trouble with memory allocation and pointers
I'm having trouble with pointers and dynamic memory. I made a class FileReader that read from a file formated like this.
FirstName,LastName,Year,GPA
String,String,String,Integer
Chris,Knight,Fr,3.8
Mitch,Taylor,Jr,3.5
The first line, I stored it in a vector called Names
and 2nd line in vector called Types.
I also made a vector that holds void pointers since it will hold arbitrary types
My question is, how can I free up those memory in the heap?
#ifndef RECORD_H
#define RECORD_H
class Record{
private:
//POINTER VARIABLES
int *intPtr;
double *doublePtr;
vector<string*> stringPtrList;
//NAMES,TYPES, AND VALUES
vector<string> Names;
vector<string> Types;
vector<void*> Values;
public:
Record(vector<string> _names, vector<string> _types, vector<string>_values){
Names = _names;
Types = _types;
//ALOCATING MEMORY
for (unsigned i = 0; i < Types.size(); i++){
string *stringPtr = new string;
stringPtrList.push_back(stringPtr);
}
for (unsigned int i = 0; i < Types.size(); i++){
if (Types[i] == "Integer"){
intPtr = new int;
*intPtr = stoi(_values[i]);
Values.push_back((void*)intPtr);
}
else if (Types[i] == "Double"){
doublePtr = new double;
*doublePtr = stod(_values[i]);
Values.push_back((void*)doublePtr);
}
else if (Types[i] == "String"){
*stringPtrList[i] = _values[i];
Values.push_back((void*)stringPtrList[i]);
}
else{
cout << "No match Type" << endl;
}
}
}
Record(const Record &r){
int *intPtr = new int;
intPtr = r.intPtr;
double *doublePtr = new double;
doublePtr = r.doublePtr;
for (int i = 0; i < r.stringPtrList.size(); i++){
stringPtrList[i] = new string;
stringPtrList[i] = r.stringPtrList[i];
}
}
~Record(){
delete intPtr, doublePtr;
for (int i = 0; i < Types.size(); i++){
delete stringPtrList[i];
}
cout << "Pointer are deleted" << endl;
}
friend ostream&operator <<(ostream &os, const Record &r){
for (unsigned int i = 0; i < r.Types.size(); i++){
if (r.Types[i] == "Integer"){
os << "Integer: " << *(int*)r.Values[i] << endl;
}
else if (r.Types[i] == "String"){
os << "String" << *static_cast<string*>(r.Values[i]) << endl;
}
else if (r.Types[i] == "Double"){
os << "Double" << *(double*)r.Values[i] << endl;
}
else{
cout << "Fatal Error!" << endl;
}
}
cin.get();
return os;
}
};
#endif
GPA has to be a float, not an int. 3.5 can not be an int.
This sounds like homework question. Even if it isn't, it sounds like you are over-complicating things. Just use a list (vector) of structs.
If you really have to be able to handle any type, just use a value-pair type of stuct, something along the lines of:
struct Record
{
string value;
VAR_TYPE type; //this is some enum you defined.
}
Keep a list of columns with types and column index, so easily process each record as you read it.
Since you know the type of each record, you can cast it to that when you are actually going to use it.
It's much cleaner that way, no need for dynamic allocation (which is slow) and messing with void pointers.
Related
I've been trying to figure out how to prevent a user from entering a duplicate value and honestly I am struggling so much for an answer that's probably really simple once I see it, but I can't. The function is below along with the struct node. I would really appreciate it if someone could help me out here.
struct node {
int data = -1;
node * current;
node * next;
};
node * start = NULL;
```
void addNode(struct node & n) {
if (n.data == -1) {
cout << "List not created yet." << endl;
} else {
node * temp;
node * temp2;
temp = new node;
cout << "What number would you like to enter:" << endl;
cin >> temp -> data;
cout << endl;
int value;
value = temp -> data;
temp = start;
while (temp != NULL) {
if (temp -> data == value) {
cout << "Duplicate Number!" << endl;
} else {
temp = temp -> next;
}
temp = temp -> next;
}
if (start == NULL) {
start = temp;
} else {
temp2 = start;
while (temp2 -> next != NULL) {
temp2 = temp2 -> next;
}
temp2 -> next = temp;
}
}
}
Here are some remarks on your code:
Don't make start a global variable. Instead make it local to main and pass it as argument to the addNode function
Use nullptr instead of NULL
Don't ask for the user's input inside the addNode function. By the principle of separation of concern, keep the I/O aspects outside that function.
Instead pass the value as argument to addNode
You should treat a node differently when it has the value -1. An empty list is not a list with one node that has the value -1. An empty list is a null pointer.
Even if a list is empty, it should be possible to add the first node with this function
Use more descriptive variable names. n for a node instance is not very clear. Also temp and temp2 are not very clear. One of the two is the newly created node, so it could be named newNode.
After you have created the new node, and assigned its reference to temp, you assign a new value to temp with temp = start, and so you've lost (and leaked) the newly created node.
In your loop, you'll execute temp = temp->next twice when the value does not match. This should of course only be done once per iteration.
Even when your code finds a duplicate and outputs a message, it still continues the process. Instead you should stop the process, and not create the node (or if you already did: dispose it with delete).
It is a pity that you need to traverse the list again from the start to find the last node and append the new node there. You should be able to do that in the first loop where you look for the duplicate.
Here is a correction:
bool addNode(node* &start, int value) {
node * current = start;
if (start != nullptr) {
while (current->data != value && current->next != nullptr) {
current = current->next;
}
if (current->data == value) {
return false; // duplicate!
}
}
node* newNode = new node;
newNode->data = value;
if (start != nullptr) {
current->next = newNode;
} else {
start = newNode;
}
return true;
}
Note that this function returns a boolean: if true then the node was inserted. The other case means there was a duplicate.
Your main function could look like this:
int main() {
// define start as local variable
node * start = nullptr; // Use nullptr instead of NULL
while (true) {
int value;
// Don't do I/O together with list-logic
cout << "What number would you like to enter:" << endl;
cin >> value;
cout << endl;
if (value == -1) break;
if (!addNode(start, value)) {
cout << "Duplicate Number!" << endl;
}
}
}
local function fShallowCopy(tData)
local tOutput = {}
for k,v in ipairs(tData) do
tOutput[k] = v
end
return tOutput
end
local function fLexTblSort(tA,tB) --sorter for tables
for i=1,#tA do
if tA[i]~=tB[i] then
return tA[i]<tB[i]
end
end
return false
end
function fBWT(tData)
--setup--
local iSize = #tData
local tSolution = {}
local tSolved = {}
--key table--
for n=1,iSize do
tData[iSize] = fRemove(tData,1)
tSolution[n] = fShallowCopy(tData)
end
table.sort(tSolution,fLexTblSort)
--encode output--
for i=1,iSize do
tSolved[i] = tSolution[i][iSize]
end
--finalize--
for i=1,iSize do
if fIsEqual(tSolution[i],tData) then
return i,tSolved
end
end
return false
end
Above is my current code for achieving BWT encoding in Lua. The issue is because of the size of the tables and lengths of loops it takes a long time to run. For a 1000 character input the average encoding time is about 1.15 seconds. Does anyone have suggestions for making a faster BWT encoding function?
the biggest slowdowns appear to be in fLexTblSort and fShallowCopy. I have included both above the BWT function as well.
If I see right, your algorithm has complexity O(n^2 log n), if the sort is quicksort. The comparator function fLexTblSort takes O(n) itself for each pair of values you compare.
As I checked with my implementation from few years back, I see possible space to improve. You create all the possible rotations of the tData, which takes also a lot of time. I used only single data block and I stored only starting positions of particular rotations. You also use a lot of loops which can shrink into less.
Mine implementation was in C, but the concept can be used also in Lua. The idea in some hybrid pseudocode between your Lua and C.
function fBWT(tData)
local n = #tData
local tSolution = {}
for(i = 0; i < n; i++)
tSolution[i] = i;
--table.sort(tSolution, fLexTblSort)
quicksort(tData, n, tSolution, 0, n)
for(i = 0; i < n; i++){
tSolved[i] = tData[(tSolution[i]+n-1)%n];
if( tSolution[i] == 0 )
I = i;
}
return I, tSolved
end
You will also need your own sort function, because the standard does not offer enough flexibility for this magic. Quicksort is a good idea (you might avoid some of the arguments, but I pasted just the C version I was using):
void swap(int array[], int left, int right){
int tmp = array[right];
array[right] = array[left];
array[left] = tmp;
}
void quicksort(uint8_t data[], int length, int array[], int left, int right){
if(left < right){
int boundary = left;
for(int i = left + 1; i < right; i++){
if( offset_compare(data, length, array, i, left) < 0 ){
swap(array, i, ++boundary);
}
}
swap(array, left, boundary);
quicksort(data, length, array, left, boundary);
quicksort(data, length, array, boundary + 1, right);
}
}
The last step is your own comparator function (similar to your original, but working on the rotations, again in C):
/**
* compare one string (fixed length) with different rotations.
*/
int offset_compare(uint8_t *data, int length, int *array, int first, int second){
int res;
for(int i = 0; i < length; i++){
res = data[(array[first]+i)%length] - data[(array[second]+i)%length];
if( res != 0 ){
return res;
}
}
return 0;
}
This is the basic idea I came up with few years ago and which worked for me. Let me know if there is something not clear or some mistake.
This is my function. It's working absolutely fine; I just can't get one more thing working.
Instead of the static fopen paths, I need the user to write the path for the files. I tried several things but I can't get it working. Please help
int FileToFile() {
FILE *fp;
FILE *fp_write;
char line[128];
int max=0;
int countFor=0;
int countWhile=0;
int countDo = 0;
fp = fopen("d:\\text.txt", "r+");
fp_write = fopen("d:\\results.txt", "w+");
if (!fp) {
perror("Greshka");
}
else {
while (fgets(line, sizeof line, fp) != NULL) {
countFor = 0;
countWhile = 0;
countDo = 0;
fputs(line, stdout);
if (line[strlen(line)-1] = "\n") if (max < (strlen(line) -1)) max = strlen(line) -1;
else if (max < strlen(line)) max = strlen(line);
char *tmp = line;
while (tmp = strstr(tmp, "for")){
countFor++;
tmp++;
}
tmp = line;
while (tmp = strstr(tmp, "while")){
countWhile++;
tmp++;
}
tmp = line;
while (tmp = strstr(tmp, "do")){
countDo++;
tmp++;
}
fprintf(fp_write, "Na tozi red operatora for go ima: %d pyti\n", countFor);
fprintf(fp_write, "Na tozi red operatora for/while go ima: %d pyti\n", countWhile - countDo);
fprintf(fp_write, "Na tozi red operatora do go ima: %d pyti\n", countDo);
}
fprintf(fp_write, "Maximalen broi simvoli e:%d\n", max);
fclose(fp_write);
fclose(fp);
}
}
Have a look at argc and argv. They are used for command-line arguments passed to a program. This requires that your main function be revised as follows:
int main(int argc, char *argv[])
The argc is an integer that represents the number of command-like arguments, and argv is an array of char* that contain the arguments themselves. Note that for both, the program name itself counts as an argument.
So if you invoke your program like this:
myprog c:\temp
Then argc will be 2, argv[0] will be myprog, and argv[1] will be c:\temp. Now you can just pass the strings to your function. If you pass more arguments, they will be argv[2], etc.
Keep in mind if your path contains spaces, you must enclose it in double quotes for it to be considered one argument, because space is used as a delimiter:
myprog "c:\path with spaces"
Last semester in an assignment the class had to model a bank account in C++. This semester we are doing the same thing except in objective-c and in the form of an iOS app. I've just begun and have a basic storyboard set up to test my deposits however I cannot get my total balance to add up and I'm pretty sure it is because I instantiate my Account object with the deposit IBAction. How should this be done properly? I only need a push in the right direction and I'm confident I can hit the ground running from there with the rest. See attached code:
- (IBAction)deposit:(id)sender {
Account *acc =[[Account alloc]init];
double damount = [_textField.text doubleValue] ;
[acc deposit:(damount)];
_display.text = [NSString stringWithFormat:#"%f", acc.getBalance];
}
Original C++ code as requested:
int main(){
char szFName[32];
char szLName[32];
char szSIN[12];
char szAccType[10];
double dBalance;
int op;
Account *acc[MAX_ACCOUNTS];
int count=0;
while (count<MAX_ACCOUNTS)
{
cout << "Customer's First Name : " << flush;
cin >> szFName;
cout << "Customer's Last Name : " << flush;
cin >> szLName;
cout << "Customer's SIN : " << flush;
cin >> szSIN;
cout << "Account Type : " << flush;
cin >> szAccType;
cout << "Opening Balance : " << flush;
cin >> dBalance;
if ( !strcmp(szAccType,"Checking") )
acc[count] = new CheckingAcc(szFName, szLName, szSIN, szAccType, dBalance);
else if ( !strcmp(szAccType,"VIP") )
acc[count] = new VIPAcc(szFName, szLName, szSIN, szAccType, dBalance);
else if ( !strcmp(szAccType,"Saving") )
acc[count] = new SavingAcc(szFName, szLName, szSIN, szAccType, dBalance);
else
{
cout << "Incorect account type." << endl;
continue;
}
count++;
}
The problem you're facing is that you're creating a new bank account every time instead of maintaining a single account and adding to it.
In your original program you created an array of accounts acc that persisted during the lifetime of the user input. Since you've moved from a procedural program to a UI program with a run loop, you'll need a more persistent place to store it.
Generally, a good spot would be a property on your view controller or higher up if the objects need to persist longer than the view controller:
#property Account *account;
...
- (id)init
{
if (self) {
_account = [[Account alloc] init];
}
return self;
}
...
[self.account deposit:(damount)];
Since this is for class, you will probably want to review your textbook for topics like properties and instance variables.
I have a text and I want to train by adding feature using the java API. Looking at the examples the main class to build the training set is the svm_problem. It appear like the svm_node represents a feature (the index is the feature and the value is the weight of the feature).
What I have done is to have a map (just to simplify the problem) that keeps an association between the feature and an index. For each of my weight> example I do create a new node :
svm_node currentNode = new svm_node();
int index = feature.getIndexInMap();
double value = feature.getWeight();
currentNode.index = index;
currentNode.value = value;
Is my intuition correct? What does the svm_problem.y refers to? Does it refer to the index of the label? Is the svm_problem.l just the length of the two vectors?
Your intuition is very close, but svm_node is a pattern not a feature. The variable svm_problem.y is an array that contains the labels of each pattern and svm_problem.l is the size of the training set.
Also, beware that svm_parameter.nr_weight is the weight of each label (useful if you have an unbalanced training set) but if you are not going to use it you must set that value to zero.
Let me show you a simple example in C++:
#include "svm.h"
#include <iostream>
using namespace std;
int main()
{
svm_parameter params;
params.svm_type = C_SVC;
params.kernel_type = RBF;
params.C = 1;
params.gamma = 1;
params.nr_weight = 0;
params.p= 0.0001;
svm_problem problem;
problem.l = 4;
problem.y = new double[4]{1,-1,-1,1};
problem.x = new svm_node*[4];
{
problem.x[0] = new svm_node[3];
problem.x[0][0].index = 1;
problem.x[0][0].value = 0;
problem.x[0][1].index = 2;
problem.x[0][1].value = 0;
problem.x[0][2].index = -1;
}
{
problem.x[1] = new svm_node[3];
problem.x[1][0].index = 1;
problem.x[1][0].value = 1;
problem.x[1][1].index = 2;
problem.x[1][1].value = 0;
problem.x[1][2].index = -1;
}
{
problem.x[2] = new svm_node[3];
problem.x[2][0].index = 1;
problem.x[2][0].value = 0;
problem.x[2][1].index = 2;
problem.x[2][1].value = 1;
problem.x[2][2].index = -1;
}
{
problem.x[3] = new svm_node[3];
problem.x[3][0].index = 1;
problem.x[3][0].value = 1;
problem.x[3][1].index = 2;
problem.x[3][1].value = 1;
problem.x[3][2].index = -1;
}
for(int i=0; i<4; i++)
{
cout << problem.y[i] << endl;
}
svm_model * model = svm_train(&problem, ¶ms);
svm_save_model("mymodel.svm", model);
for(int i=0; i<4; i++)
{
double d = svm_predict(model, problem.x[i]);
cout << "Prediction " << d << endl;
}
/* We should free the memory at this point.
But this example is large enough already */
}