Accessing a Dynamic Array causing a runtime error - c++

I've been messing around with dynamic memory and I've hit a huge wall.
I'm trying to create a program where the user enters as many strings as they want, then can quit whenever, however after a second string is entered, the program crashes with out giving me any specific error message.
#include "stdafx.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "new"
int _tmain(int argc, _TCHAR* argv[])
{
//Variables
int i=0,end=0,requiresSize=1;
char ** temp;
char item[256]="a";
char ** requires;
//Initialize each element in requiers
requires = new char * [requiresSize];
for(int j=0;j<requiresSize*2;j++){
requires[j]= new char[256];
}
while(strcmp(item,"q-")){
end=0;
printf("Enter h- for help.\nEnter q- to quit.\n");
printf("Please enter a string\n");
gets_s(item);
if(!strcmp(item,"h-")){
printf("Enter a string to add to the list.\nEnter p- to print the list.\n");
end=1;
}
if(!strcmp(item,"q-")){
break;
}
if(!strcmp(item,"p-")){
if(requires[0]!=NULL){
for(int j=0;j<requiresSize;j++){
printf("%d. %s\n",j,requires[j]);
}
}
end=1;
}
while(end==0){
printf("check1:i=%d\n",i);
//if search index is larger than size of the array,reallocate the array
if(i>= requiresSize){
temp = new char * [requiresSize*2];
//Initialize each element in temp
printf("check2:temp initalized\n");
for(int j=0;j<requiresSize*2;j++){
temp[j]= new char[256];
}
printf("check3:temp itmes initialized\n");
for(int j =0;j<requiresSize;j++){
//for each element in requires, copy that element to temp
temp[j]=requires[j];
}
printf("check4:copied requires into temp\n");
delete * requires;
requires = temp;
printf("check5:deleted requires and set requires equal to temp\n");
delete temp;
requiresSize = requiresSize *2;
}
printf("check6:\n");
//if the index at requires is not empty, check to see if it is the same as given item
if(requires[i]!= NULL){
printf("check8:index at requires is not empty\n");
//I know the error occurs here, something to do with accessing requires[i]
if(!strcmp( item, requires[i])){
printf("check9:index at requires is the same as item\n");
//if they are the same, break out of the loop, item is already included
break;
}else{
printf("check10:index at requires is different\n");
//otherwise, increase the index and check again (continue loop)
i++;
break;
}
}else{
printf("check11:index at requires is null, item added\n");
//if the index is empty, add the item to the list and break out of loop
requires[i]= item;
break;
}
printf("check7\n");
}
}
delete requires;
return 0;
}
Thank you in advance.

You need to realize that an assignment statement such as temp = requires (in this case) is only copying over the pointer, so that temp is now pointing to the same location in memory as requires; it does NOT copy over that memory.
This is leading to two problems:
You are allocating new 256-char arrays to each element of temp, and then reassigning each char* in temp to point to a different location, leaking all of that memory; there is now no way to reference the newly-allocated memory, and thus no way for you to free it.
You are assigning the pointer temp to requires, which, again, just means the two are now pointed to the same location in memory, and then deleting temp, which frees that memory (that, again, requires is also now pointing to).
Also, if you use new[] to allocate an array, you must use delete[] to free it. So requires = new char * [requiresSize]; requires you to use delete [] requires; at the end of the program, instead of just delete requires;. Same for each 256-char element of requires.
So, replace temp[j]=requires[j]; with an appropriate call to strcpy (or strncpy). And do not delete temp; the delete [] requires; at the end will handle that, since it is now pointing to that bit of memory.

Related

Why is the 2nd level of the pointers in a hash table not need malloc() to allocate memory?

I am currently learning separate chaining to resolve collisions in hashing. Below shows an example that creates a hash table. I see hash_tbl *new_table = malloc(sizeof(hash_tbl)); allocates a big chunk of memory for new_table. Next, new_table->list = malloc(sizeof(node *) * size); seems to divide new_table by size to store the 1st level of pointer of node **list.
Q1: The part I can't figure out is that why I do NOT need to malloc() the 2nd level of the pointer at node **list; marked by ###?
Q2: Since the code is correct, does for (int i=0; i<size; i++){
new_table->list[i] = NULL; } initialize the head pointer of the linked list pointed to by new_tbl->list[i]?
p.s. Could someone can illustrate his explanation graphically?
typedef struct Node {
char *str;
struct Node *next;
} node;
typedef struct Hash_Tbl {
int size;
node **list; //###
} hash_tbl;
int main() {
int size = 6;
create_hash_table(size);
}
hash_tbl *create_hash_table(int size) {
if (size < 1) return NULL;
hash_tbl *new_table = malloc(sizeof(hash_tbl));
if (new_table == NULL) return NULL;
new_table->list = malloc(sizeof(node *) * size);
if (new_table->list == NULL) return NULL;
// Initialize the elements of the hash table
for (int i=0; i<size; i++){
new_table->list[i] = NULL;
}
new_table->size = size;
return new_table;
}
I can't figure out is that why do I NOT need to malloc() the 2nd level of the pointer at node **list;
Since the hash table starts off empty, you do not need to allocate the 2nd level yet. The code of create_hash_table sets all buckets to NULL to indicate that they are empty.
does [for loop] initialize the head pointer of the linked list pointed to be new_tbl->list[i]?
There isn't one "head pointer" in a hash table. Each element of the list[] array is a head pointer of its own. All these pointers are initialized to NULL, indicating that their corresponding bucket is empty.
Initially, all bucket lists are empty. When you start adding items to the hash table, the lists start filling in.
The diagram below shows a hash table with six buckets. Buckets 1 and 3 have some items; the remaining buckets are empty. Bucket 1 has no collisions, while bucket 3 has a two-way collision.
The part I can't figure out is that why do I NOT need to malloc() the 2nd level of the pointer at node **list; marked by ###?
The 2nd level of pointer will be allocated whenever required. This is just the initialization part and that is why we simply initialize it to NULL here.
Since the code is correct, does for (int i=0; ilist[i] = NULL; } initialize the head pointer of the linked list pointed to be new_tbl->list[i]?
Consider new_table->list as an array of pointers. With each element representing a chain of nodes. So, in a sense you are correct. Each element of this array could be a head to the respective chains/buckets you are going to form later on.

Deleting an element from an array of objects

I tried to write a function that gets an object ("Stone") and deletes the stone from a given array. code:
void Pile::del_stone(Stone &s)
{
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i <size;++i)
{
if (s != Pile_arr[i])//if the given object to delete is different from the current
{
temp[i] = Pile_arr[i];//copy to the new array
}
else
{
i--;
}
}
Pile_arr = temp;
set_size(this->size - 1);
temp = NULL;
delete[] temp;
}
Pile_arr is a member of Pile class.
The problem is that i get an infinite loop, because i decrease i. I cant figure out how to solve this issue. Any ideas?
Use two indexes: i and j. Use i to know which element of the original array you are looking and j to know where to put the element in temp.
You need to use a separate counter to track where new elements should be placed.
I have used n below:
Stone *temp = new Stone[size - 1];
int n = 0; // Stores the current size of temp array
for (int i = 0;i <size;++i) {
if (s != Pile_arr[i]) {
temp[n++] = Pile_arr[i];
}
}
It's also worth considering the case where s is not found in the array, as this would cause a runtime error (Attempting to add size elements to an array of size size - 1).
Using a STL container would be a far better option here.
This function will:
Allocate a new array of length size-1
Search for the intended object
If you find it, copy it to the same exact position in the array
If you don't --i
Finally, ++i
First of all, this function is bad for 3 reasons:
It only copies one item over--the given item. You have an array with only 1 object.
It copies the item from index to index. Since the final array is one smaller, if the object is at the max original index, it will be out of bounds for the new array.
If the object is not immediately found, the array will get stuck, as you decrease the index, and then increase it using the loop--you'll never move again.
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i
Instead:
Cache the found object, then delete it from the original array or mark it. temp = found object
Copy the array, one by one, without copying empty spaces and closing the gap. Copy temp_array[i] and increment i if and only if temp_array[j] is not marked/deleted. Increment j
Decide where to put the found object.
Once again, you can decide to use separate indexes--one for parsing the original array, and one for filling the new array.

free() detecting heap corruption

When using Visual Studio 2013 heap corruption is detected on calling free().
It is not detected on Linux.
My code seems to run fine until it hits the free function. I call free many times, but in one specific instance, it causes a window to pop up saying HEAP CORRUPTION DETECTED.
I've allocated memory to store pointers to strings(words) for two sets of words. For the first set of words, upon freeing them, no error message is given.
For the second set of words, upon freeing them, the error message pops up.
Here is the code for the first set of words, I made an array of words called arrayFictionary. The function takes a pointer to the array of pointers and adds on new words. No error message is given upon freeing(arrayFictionary).
void ConvertFictionary(char*** parrayFictionary, char* fictionary) {
char * pTemp = 0;
int32_t count = 1;
// put first fictionary word into an array
if(!(pTemp=strtok(fictionary, "\n"))) {//if the dictionary end is reached,
(*parrayFictionary)[count-1] = pTemp; // exit while loop
goto skipD;
}
*parrayFictionary = (char**) realloc(*parrayFictionary, (count + 1)*sizeof(char*));
(*parrayFictionary)[count-1] = pTemp;
count++;
while(1) {// put fictionary words into an array, exit when done
if(!(pTemp=strtok(NULL, "\n"))) {//if the dictionary end is reached,
(*parrayFictionary)[count-1] = pTemp; // exit while loop
break;
}
*parrayFictionary = (char**) realloc(*parrayFictionary, (count + 1)*sizeof(char*));
(*parrayFictionary)[count-1] = pTemp;
count++;
}
skipD:
return;
}
Here is the code for allocating an array for my second set of words called arrayFarticle. Same method is used with slight differences. Error message results upon calling free(arrayFarticle).
void ConvertFarticle(char*** parrayFarticle, char* farticle)
{
char * pTemp = 0;
int32_t count = 1;
// put first farticle word into an array
if(!(pTemp=strtok(farticle, "0123456789.,;: '\"\n!##$%%^&*()_-+=|\\[]{} <>?/~`’"))) //if the farticle end is reached, exit while loop
{
(*parrayFarticle)[count-1] = pTemp;
goto skipA;
}
if(strlen(pTemp)>=2)
{
*parrayFarticle = (char**) realloc(*parrayFarticle, sizeof(char*)*count + sizeof(char*)*2);
(*parrayFarticle)[count-1] = pTemp;
count++;
}
while(1) // put farticle words into an array, exit when done
{
if(!(pTemp=strtok(NULL, "0123456789.,;: '\"\n!##$%%^&*()_-+=|\\[]{}<>?/~`’"))) //if the farticle end is reached, exit while loop
{
(*parrayFarticle)[count-1] = pTemp;
break;
}
if(strlen(pTemp)>=2)
{
*parrayFarticle = (char**) realloc(*parrayFarticle, sizeof(char*)*count + 1);
(*parrayFarticle)[count-1] = pTemp;
count++;
}
}
skipA:
return;
}
I honestly don't know what's going on. I made sure that arrayFarticle isn't being written past its allocated limit.
Your last call to realloc results in *parrayFarticle pointing to a block with an odd (in the mathematical sense) size, and (quite likely) too small.

C++ array_put()

Hello i have question about C++ infinity arrays. Does this array_put() function by creating new array is best way to increase array size? Maybe there are faster ways than this? :(
Here whot i using and unsure about this...
#include <windows.h>
#include <iostream>
#include <sstream>
using namespace std;
// ============================================================
// ALERT WINDOW
// ============================================================
void alert(string value, string title = "Warning")
{
MessageBox(NULL, value.c_str(), title.c_str(), MB_OK);
}
// ============================================================
// ============================================================
// INTEGER TO STRING
// ============================================================
string integer_to_string(int value)
{
ostringstream stream;
stream<<value<<flush;
return stream.str();
}
// ============================================================
// ============================================================
// ARRAY PUT
// ============================================================
typedef struct ARRAY{
int* data;
int length = 0;
} array;
void array_put(array &array_data, int value)
{
int* new_array = new int[array_data.length+1];
if (array_data.length != 0){new_array = array_data.data;}
new_array[array_data.length] = value;
array_data.data = new_array; array_data.length++;
}
// ============================================================
// ============================================================
// ARRAY PRINT (REQ: ARRAY PUT)
// ============================================================
string array_print(array array_data)
{
string out = "";
out += "array_length: " + integer_to_string(array_data.length) + "\n";
for (int i=0;i < array_data.length;i++)
{
out += "[" + integer_to_string(i) + "] = " + integer_to_string(array_data.data[i]) + "\n";
}
return out;
}
// ============================================================
int main()
{
array array_data;
array_put(array_data, 120);
array_put(array_data, 170);
string result = array_print(array_data);
alert(result);
return 0;
}
Others already have pointed out the errors in your code, and pointed you to the fact that you probably should use vector instead of a home-grown solution. However nobody has yet addressed your actual question whether there's a faster method.
Assuming you typically add more than one element to the same array, this is indeed not optimal: As is (after correcting the errors), you'll reallocate the array for every single additional entry, complete with copying all the data previously stored. Since that data will grow with every element, you get quadratic complexity of insertions (the number of copies that have to be made is proportional to the square of the number of elements you insert), and a linear number of expensive reallocations.
A better strategy is to always allocate a certain fraction of the number of existing elements as new elements, and keeping track of how many of those elements are actually part of the array, and how many are just already preallocated for adding new elements later. That reduces the number of reallocations the more, the larger your array already is, and ultimately gives you an amortized constant complexity (on average, the number of copies to perform is proportional to the number of elements you insert), and a logarithmic number of expensive reallocations.
Indeed, that is exactly what vector does.
There are multiple problems in your code. First of all
new_array = array_data.data;
does not copy the content of the old array to the new array, it just assigns the pointer, so after that new_array is the same as array_data.data. You could use memcpy here:
memcpy(new_array, array_data.data, sizeof(int)*array_data.length);
You also need to free the old array data before asigning the new storage to avoid leaks, so:
delete [] array_data.data;
array_data.data = new_array;
After you make your code to work correctly, you can think about allocating more storage to avoid allocating new array in every array_put.
Function array_put is simply invalid. For example there is a memory leak in your function. At first you allocated memory and assigned its address to new_array and in the next statement you reassigned new_array. So the address of the allocated memory was lost.
I think that instead of this
void array_put(array &array_data, int value)
{
int* new_array = new int[array_data.length+1];
if (array_data.length != 0){new_array = array_data.data;}
new_array[array_data.length] = value;
array_data.data = new_array; array_data.length++;
}
you meant the following
void array_put( array &array_data, int value )
{
int *data = new int[array_data.length+1];
std::copy( array_data.data, array_data.data + array_data.length, data );
data[array_data.length] = value;
delete [] array_data.data;
array_data.data = data;
++array_data.length;
}
Of course it would be better if you would use standard class std::vector instead of manually allocating an array.
Quite apart from your solution not working, increasing the size by 1 each time means that adding N items will require O(N * N) copies - you copy 1 item, then 2, then 3, and so on.
Just use vector. It works, and it is guaranteed to add an element in constant time on average.

glibc detected - double free or corruption

I get the following error messages when I submit the code (pasted below) to an online gcc compiler.
* glibc detected /run-1326102706-2046832693/solution: double free or corruption (!prev): 0x091901a8 ** =======
The code is as follows:
# include <iostream>
# include <string>
# include <list>
# include <cstring>
using namespace std;
int main()
{
int test_cases, i, score, str_len;
string str;
char first_char, current_char;
list <int> strlist;
list <int> :: iterator it;
cin>>test_cases;
char *cstr[test_cases]; //Creating an array of cstr pointers (test_cases number of pointers)
while(test_cases > 0)
{
cin>>str;
first_char = str.at(0);
str_len = str.length();
score = str_len;
strlist.clear();
cstr[test_cases-1] = new char[str_len];
strcpy(cstr[test_cases-1],str.c_str()); //copying the input str into cstr. This is done to minimize the complexity of std::string's at function.
for(i=1;i<str_len; i++)
{
current_char = *(cstr[test_cases-1]+i);
if (current_char == first_char)
{
score++; strlist.push_front(1);
it = strlist.begin();
if (it != strlist.end())
it++;
}
while (!strlist.empty() && it != strlist.end())
{
if (current_char == *(cstr[test_cases-1] + *(it)))
{
(*it)++;it++;score++;
}
else
it = strlist.erase(it);
}
if (!strlist.empty())
it = strlist.begin();
}
cout<<score<<endl;
delete(cstr[test_cases-1]);
test_cases--;
}
return 0;
}
As mentioned in the code itself, I initially used std::string, but found that the std::string.at function was quite slow (esepcially since this problem has really large input strings). So I decided to store the string input in a character array, so that direct indexing to a particular position would be possible.
Appreciate any help.
There are two problems that I can see:
cstr[test_cases-1] = new char[str_len]; // Not allocating space for terminating NULL.
delete(cstr[test_cases-1]); // Incorrect delete, should be delete[]
// As already pointed out by mooware
Change these two lines to:
cstr[test_cases-1] = new char[str_len + 1];
delete[] cstr[test_cases-1];
You are using array-new ("new char[str_len]") to allocate the strings, but scalar-delete ("delete(cstr[test_cases-1])") to delete them. You should always match the new- and delete-operators, so when you use array-new, also use array-delete ("delete[] cstr[test_cases-1]").
You have two bugs. One is here:
cstr[test_cases-1] = new char[str_len];
strcpy(cstr[test_cases-1],str.c_str());
You allocate one byte too few. That should be new char[str_len+1] since strcpy copies the terminator.
The other is here:
delete(cstr[test_cases-1]);
You cannot allocate with new[] and deallocate with delete. If you allocate with new[], you must deallocate with delete[].