So i'm trying to write a function which would get input from keyboard and store it in the 2d dynamic array. n is the number of lines (tried with 1-4 lines), m is the number of characters per line (256 in my case). I've read plenty about dynamic arrays and the use of new and the code seems totaly fine to me, but i keep getting this error when i try to enter the text: Access violation reading location 0x00000000. Can't figure out why. Please help.
void KeyInput (char **string, unsigned int n, unsigned int m)
{
cout<<endl<<"Input from keyboard"<<endl;
string=new char* [n];
for(unsigned int i = 0; i < n; i++ )
string[i]=new char[m];
for(unsigned int i = 0; i < n; i++ )
gets(string[i]);
}
can you give more information on where you are getting the access violation? I tried the following code (Visual Studio 2010, Window 7 Professional) and did not get an error. Note that I did change the characters per line to 15 instead of 255 as I wanted to test boundary conditions without a lot of typing.
Your function seems to work fine on my machine, however you do have a latent buffer-overflow using gets as it does not check for the length of the string. Remember that gets will append a null-terminator for you, so if in your case you enter exactly 255 characters you will overflow your buffer by one.
void KeyInput(char** string, unsigned int n, unsigned int m);
int _tmain(int argc, _TCHAR* argv[])
{
char* strArray;
KeyInput(&strArray, 4, 15);
return 0;
}
void KeyInput(char** string, unsigned int n, unsigned int m)
{
string = new char*[n];
for(unsigned int i = 0; i < n; i++)
{
string[i] = new char[m];
}
for(unsigned int i = 0; i < n; i++)
{
gets(string[i]);
}
}
(also ignore the hideous _tmain and _TCHAR stuff, they are Windows idiosyncrasies :) ).
Finally, unless this is an assignment (or an exercise for self learning), do what 40two suggested and use STL to make your life easy.
Use a vector of strings, take advantage of the force that STL has (use the force Luke see code below how):
void KeyInput (std::vector<std::string>& str_vec, int const n)
{
std::cout << "\nInput from keyboard" << std::endl;
for (auto i = 0; i < n; i++) {
std::string tmp;
std::getline(std::cin, tmp);
str_vec.push_back(tmp);
}
}
Update or Why your C++ teachers are wrong:
void KeyInput(char ***string, unsigned int n, unsigned int m)
{
std::cout << "\nInput from keyboard" << std::endl;
*string = new char*[n];
for (unsigned int i = 0; i < n; i++)
(*string)[i] = new char[m];
for (unsigned int i = 0; i < n; i++)
std::gets((*string)[i]);
}
int main()
{
char **string = 0;
KeyInput(&string, 4, 100);
for (auto i = 0; i < 4; ++i) std::cout << string[i] << std::endl;
return 0;
}
You need triple pointers in order to pass the 2d array by reference and to be properly filled (OMG!!!).
The user can enter only limited length strings (e.g., 99) don't forget strings have one character at the end (i.e., '/0' the null character).
You have to take care of the memory allocated and deleted later in order to avoid memory leaks.
If you want to shoot your self in the foot continue to program like this.
Related
I need some help since I'm new to c++, I have a homework question where we should read a name to a char[] and then place that input inside a dynamic array, sort the dynamic array, and then terminate the allocated memory. We have to work with a half-done written program and I don't think I'm getting the input incorrectly in the dynamic array and I have a problem with deallocating memory could someone help with some tips maybe? My contribution to the code is highlighted in ** ** thanks!
const int BUFLEN = 100; // Max length of reading buffer
void sort(char* friendList[], int n); // n is the number of elements
void print(char* friendList[], int n); // n is the number of elements
void terminate(char* friendList[], int n); // n is the number of elements
const int AMOUNT = 5;
int main()
{
char* friends[AMOUNT]; // Dynamic array with AMOUNT pcs of string pointers
char buff[BUFLEN] = { "" }; // Creates a string buffer (null terminated)
int count = 0;
while (count < AMOUNT) // enter AMOUNT number of friends
{
cout << "Name a friend: ";
cin.getline(buff, BUFLEN); // Temporary reading into string buffer
friends[count] = **new char[AMOUNT];** //. . . WRITE CODE allocating memory to the string
// WRITE CODE that adds loaded name to current location in the dynamic array
**strcpy(friends[count], buff);**
++count;
}
sort(friends, count); // Sorts the ‘count’ strings
print(friends, count); // Prints the ‘count’ first names
terminate(friends, count);// Releases all allocated memory space
return 0;
}
void sort(char* friendList[], int n)
{
// WRITE FUNCTION that sorts the strings in the friendList in alphabetical order!
**int result;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
result = strcmp(friendList[j+1], friendList[j]);
if (result < 0)
swap(friendList[j+1], friendList[j]);
}
}**
}
void print(char* friendList[], int n)
{
// WRITE FUNCTION that prints ‘n’ names from the friendList on screen!
**for (int i = 0; i < n; i++)
{
cout << friendList[i] << " " << i << endl;
}**
}
void terminate(char* friendList[], int n)
{
// WRITE FUNCTION that releases all dynamically allocated memory!
**for (int i = 0; i < n; i++)
{
delete friendList[i];
}
delete [] friendList;
cout << "deleted! ";**
}
I see a few problems with this code:
In main():
not validating that cin.getline() is successful before using the contents of buff.
AMOUNT is the wrong size to use when allocating a new char[] to store in friends[]. The correct size should be either strlen(buff)+1 or cin.gcount().
In terminate() (not to be confused with std::terminate()):
delete[]'ing the input array itself, which was not allocated with new[] to begin with and thus must not be delete[]'ed.
Instead of this statement
friends[count] = new char[AMOUNT];
you need to write
friends[count] = new char[strlen( buff ) + 1];
Pay attention to that the array friends itself is not allocated dynamically. But each its element points to a dynamically allocated array. So the function terminate can look like
void terminate(char* friendList[], int n)
{
// WRITE FUNCTION that releases all dynamically allocated memory!
for (int i = 0; i < n; i++)
{
delete [] friendList[i];
friendList[i] = nullptr;
}
cout << "deleted! ";
}
Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}
int main(int argc, const char * argv[]) {
int N,M;
std::cin >> N;
std::cin >> M;
bool member[N];
for (int i= 0; i < N ; i++) {
member[i] = false;
}
int test[M][N];
int testSize[M];
/*//std::fill_n(testSize, M, 0);
for (int i = 0; i < M; i++) {
std::fill_n(test[M], N, -1);
}*/
for (int i = 0; i < M; i++) {
for (int j = 0; j < N ; j++) {
test[i][j] = -1;
}
testSize[i] = 0;
}
}
This is my c++ code above, that is simple code, isn't it?
But When the program got M as 100000 and N as 1000, there is EXC_BAD_ACCESS at second for loop.
I do not know why it is happening.
When smalle size data is put into, there is no error, but This case made it an error.
I'm solving an algorithm problem and confronting unknowing error.
Is there any point to fix at my program?
As you see my code, what I want is to initialize the array test and testSize to the same value; -1 and 0.
int test[M][N]; allocates an array of M*N elements on the stack. When M == 100000 and N==1000 it is an array of 100 million elements. int is usually at least 4 bytes, so you are trying to allocate 400MB array on a stack, which won't fit with default (or probably any at all) linker settings.
What you can do is to allocate that much memory on heap using malloc or new[]. You can also use 3rd-party classes for operating matrices that will do it for you.
I'm currently making a code on the MU game using dynamic arrays, and I've got a problem with printing a sequence.
Rule: If the first character is denoted by the character M, and the rest of the sequence is denoted by R, then the new sequence is MRR.
Examples include:
Current sequence: MIUI
New sequence: MIUIIUI
Current sequence: MUM
New sequence: MUMUM
Current sequence: MU
New sequence: MUU
Here are snippets of my code:
IN MAIN:
if (userchoice == 2)
{
if (rule2valid == false)
{
cout << "This rule may not be applied to your input." << endl;
return 0;
}
int newsize = size + size - 1;
char *resultant = new char[newsize];
resultant = applyRule2(userinput, size);
printarray (resultant, newsize);
}
In the function which applies the rule:
char *applyRule2(char* sequence, int size)
{
int newsize = size + size - 1;
int j = 1;
char* applyRule = new char[newsize];
for (int i = 0; i < size; i++)
applyRule[i] = sequence[i];
for (int i = size; i < newsize; i++)
{
applyRule[i] == sequence[j];
}
return applyRule;
}
and the function for printing:
void printarray(char* sequence, int size)
{
for (int i = 0; i < size; i++){
cout << sequence[i] << "\t";
}
cout << "The length of this array is : " << size;
cout << endl;
}
The problem is that when I run the program, my output is as such:
Input: M U M
Output: M U M, The length of this string is 5. (supposed to be M U M U M)
Input: M I U I
Output: M I U I, the length of this string is 7. (supposed to be M I U I I U I)
What I have done so far is that I allocated a new dynamic array with the new size, and added values into the array accordingly. I am, however, at a loss as to whether the problem lies in the applyRule2 function or in the printarray function.
It would be greatly appreciated if someone could point me out in the right direction.
There are a few error in your code. As Alf says you really should use std::string. but anyway here are some of the errors.
for (int i = size; i < newsize; i++)
{
applyRule[i] == sequence[j];
}
should be
for (int i = size; i < newsize; i++)
{
applyRule[i] = sequence[j];
}
You had a double equals == when you should have written one equals =. Your compiler should have warned you about this, pay attention to compiler warnings.
Another error
char *resultant = new char[newsize];
resultant = applyRule2(userinput, size);
should be
char *resultant = applyRule2(userinput, size);
The code you have written allocates some memory and then on the very next line it throws away that memory and instead uses the memory you allocated in applyRule2. So this isn't actually a bug, but it is a waste of resources. Your program will never get back the wasted memory. This is called a memory leak.
just use std::string instead of raw arrays and raw pointers and new
It must be pretty simple but i am so numb right now to think clearly.
So this is a small part of my code everything works fine except this.
What i actually wanted to do is infile1.open(temp2->path); but it's not possible since temp2 is a string. So i want to put this string into a char array like char p[100] to use infile1.open(p). It compiles but after some seconds boom: Stack around p was corrupted
char p[100];
while( temp2 != 0)
{
stringToCharArray(temp2->path, p);
infile1.open(p);
checkingWords(infile1, stopWords, invertedIndex);
infile1.close();
temp2 = temp2->next;
}
void stringToCharArray(string s, char *c)
{
int i;
int size = s.size();
for( i=0; i<=size ; i++)
{
c[i] = s[i];
}
}
I believe you want std::string::c_str.
infile1.open(temp2->path.c_str());
(Be careful, this const char * is only valid until the next time you change something in the std::string you get it from, in this case temp2->path).
It looks like the main error with your existing code is for( i=0; i<=size ; i++) should be i<size. But let's not go into that in too much detail, as you shouldn't really do it this way anyway.
You can do it the easy way
infile1.open(temp2->path.c_str());
But your hard way should look like this
void stringToCharArray(string s, char *c)
{
int i;
int size = s.size();
for( i=0; i<size ; i++) // < not <=
{
c[i] = s[i];
}
c[size] = '\0';
}
Of course the hard way is going to fail if your string happens to be 100 characters or more.
You can simply do:
infile1.open(temp2->path.c_str());
The stack corruption occurs inside your stringToCharArray function.
for( i=0; i<=size ; i++)
//^^^should not reach size-1, equal redundant