Here is the code::
#include <iostream>
using namespace std;
const int MAX = 4;
int main ()
{
char key[20];
char *names[MAX];
for (int i=0; i<MAX; i++)
{
cout << " entr keys\n";
cin >> key;
names[i]=key;
cout<< names[i];
}
for(int i=0; i<MAX;i++)
{
cout << names[i];
}
return 0;
}
When I enter the keys and print them in the 1st for loop they show the right value, but when I print names[i] in the 2nd for loop it keeps showing the last key entered again and again.
Please tell me: where am I going wrong?
When you run names[i]=key; you don't really copy key's string value to names[i].
It just makes name[i] point to where key is (since both name[i] & key are pointers).
so all in all you're overwriting key several times, and making all of names pointers point to key.
You need to copy those strings either by working with std::string instead of char* or by using strcpy. I'd recommend on working with std::string.
Using std::string your code should look like this:
#include <iostream>
#include <string>
using namespace std;
const int MAX = 4;
int main ()
{
string names[4];
for (int i = 0; i < MAX; i++)
{
cout << "entr keys" << endl;
cin >> names[i];
cout << names[i];
}
for(int i=0; i<4;i++)
{
cout << names[i];
}
return 0;
}
Every time you execute the lines
cout << " entr keys\n";
cin >> key;
you're inserting a null-terminated string into key, e.g. "hello\0".
Afterwards you copy key's address and store it into a cell of the names pointers array:
names[i]=key; // Now I point to 'key'
cout<< names[i];
then the cycle starts again. Anyway from the second time on you're inserting null-terminated strings into key and thus overwriting the previous contents. The second time if you had entered "hi\0" the contents of the key array would become
['h', 'i', '\0', 'l', 'l', 'o', '\0']
anyway you're going to only print the first string since the null terminator will prevent the other content from being displayed.
When the program ends you're going to have four pointers to the same key array and that array will only contain the last element inserted which overwrote the previous ones.
In order to solve you can make your array a bidimensional one (or use a string array):
const int MAX = 4;
int main ()
{
char key[4][20]; // <- Now this has two indices
char *names[4];
for (int i = 0; i < MAX; i++)
{
cout << " entr keys\n";
cin >> key[i];
names[i]=key[i];
cout<< names[i];
}
for(int i=0; i<4;i++)
{
cout << names[i];
}
return 0;
}
Live Example
Corrected program:
#include <iostream>
using namespace std;
#include <cstring>
const int MAX = 4;
int main ()
{
char key[20];
char *names[MAX];
for (int i = 0; i < MAX; i++)
{
cout << " entr keys\n";
cin >> key;
names[i] = new char[strlen(key) + 1];//names[i]=key;
strcpy(names[i], key);
cout<< names[i];
}
for(int i=0; i<MAX;i++)
{
cout << names[i];
}
for(int i=0; i<MAX;i++)
{
delete [] names[i];
}
return 0;
}
You need to allocate space for each names[i] and when done, deallocate
also, changed the hardcoded 4 to MAX
Related
I'm on exercise 4.34 of the book C++ Primer, 4th edition, which states "Write a program to read strings into a vector. Now, copy that vector into an array of character pointers. For each element in the vector, allocate a new character array and copy the data from the vector element into that character array. Then insert a pointer to the character array into the array of character pointers." I'm also trying to print the vector and character pointer array, and delete the character pointer array afterwards.
Here's what I've come up with so far:
#include <iostream>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main()
{
cout << "Enter some strings:" << endl;
vector<string> svec;
string input;
while (cin >> input) {
svec.push_back(input);
}
size_t sarr_sz = svec.size();
char **sarr = new char*[sarr_sz];
size_t carr_sz, carr_num;
char *carr = NULL;
for (vector<string>::size_type i = 0; i < svec.size(); ++i) {
carr_num = i;
carr_sz = svec[i].size();
carr = new char[carr_sz + 1];
size_t cval;
for (string::size_type j = 0; j < svec[i].size(); ++j) {
cval = j;
carr[cval] = svec[i][j];
}
cval = svec[i].size();
carr[cval] = '\0';
sarr[carr_num] = carr;
}
cout << "Vector contents:" << endl;
for (vector<string>::size_type i = 0; i < svec.size(); ++i) {
cout << svec[i] << " ";
}
cout << endl;
cout << "Character pointer array contents:" << endl;
for (size_t i = 0; i < sarr_sz; ++i) {
cout << sarr[i] << " ";
}
cout << endl;
for (size_t i = 0; i < sarr_sz; ++i) {
delete [] sarr[i];
}
delete [] sarr;
return 0;
}
When I compile and run this program, it freezes at the point after entering the string input and displays no output. When I exit the program manually using Ctrl-C, it displays either Vector Output: <first string inputted> or just Vector Output:. I've gone over the program multiple times and can't figure out where I've made an error.
Please keep in mind that I'm a beginner, and I'm just following the conventions of the book. As such, my program is probably neither efficient nor follows correct style. Any help would be greatly appreciated. Thank you.
Can someone please let me know why one can't take an input in arrays of pointer to strings using input stream as in the following code:
char *names[5];
for(int i=0; i<5; i++)
{
cout<<"enter name "<<i+1;
cin>>names[i];
}
The variable "names" is an undefined array of char pointers. That's your first problem. The pointers are undefined and have no memory allocated for them.
In your original code example there are five char pointers with undefined values. This is why the program would crash, because it's trying to access memory of the invalid address in the pointers.
Another problem is that there is no memory allocated to hold the array of chars coming in from stdin.
You could do something like this to get your original example working without crash:
#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, char** argv)
{
char names[5][128];
memset(names, 0, sizeof(names));
for (int i = 0 ; i < 5 ; i++ )
{
cout << "enter name " << i+1 << ": ";
cin >> names[i];
}
for (int i = 0 ; i < 5 ; i++ )
{
cout << names[i] << "\n";
}
}
This allocates an array of 5 128 character strings. It also clears the arrays with the memset() as well.
Since this is C++ it would seem to make more sense to do it C++ style.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int NUM_NAMES = 5;
int main(int argc, char** argv)
{
vector<string> names;
names.resize(NUM_NAMES);
for (int i = 0 ; i < NUM_NAMES ; i++ )
{
cout << "enter name " << i+1 << ": ";
cin >> names[i];
}
for (int i = 0 ; i < NUM_NAMES ; i++ )
{
cout << names[i] << "\n";
}
}
Disclaimer:
using char* for reading from std::cin is generally a bad idea and I suggest you learn how to use std::string in future.
Also this question would have been better suited for codereview.SE but I'll ignore that for now.
Here is an example of doing what you want to do, but I strongly insist you avoid doing it in any real code.
char * names[5];
// Allocate names
for (int i = 0; i < 5; i++)
{
// Use 256 characters as a buffer
// any names longer than that might cause errors
names[i] = new char[256];
}
// Do IO
for (int i = 0; i<5; i++)
{
// Append std::endl
std::cout << "enter name " << i + 1 << std::endl;
// This isn't very robust since the user can give anything as a name,
// and they can't use spaces because of how cin works in this example.
std::cin >> names[i];
}
// Use names
for (int i = 0; i < 5; i++)
{
// Printing names is just an example
// you could write the names to somewhere more important
// you could copy them to a smaller location to use less memory
std::cout << names[i] << std::endl;
}
// Dispose of names when done
for (int i = 0; i < 5; i++)
{
// Check pointer isn't null
if (names[i] != nullptr)
{
// Never forget to delete
delete names[i];
}
}
Here is the assignment:
Write a program that reads in a text file one word at a time. Store a word into a dynamically created array when it is first encountered. Create a paralle integer array to hold a count of the number of times that each particular word appears in the text file. If the word appears in the text file multiple times, do not add it into your dynamic array, but make sure to increment the corresponding word frequency counter in the parallel integer array. Remove any trailing punctuation from all words before doing any comparisons.
Create and use the following text file containing a quote from Bill Cosby to test your program.
I don't know the key to success, but the key to failure is trying to please everybody.
At the end of your program, generate a report that prints the contents of your two arrays in a format similar to the following:
Word Frequency Analysis
I 1
don't 1
know 1
the 2
key 2
...
Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int readInFile (string tempArray [], string file, int arraySize);
int main()
{
ifstream inputFile;
string *readInArray = 0,
*compareArray = 0,
filename,
word;
int wordCount = 0;
int encountered = 0;
int j = 0,
*wordFrequency = 0;
cout << "Enter the filename you wish to read in: ";
getline(cin, filename);
inputFile.open(filename.c_str());
if (inputFile)
{
while (inputFile >> word)
{
wordCount++;
}
inputFile.close();
readInArray = new string[wordCount];
readInFile(readInArray, filename, wordCount);
}
else
{
cout << "Could not open file, ending program";
return 0;
}
compareArray = new string[wordCount];
wordFrequency = new int[wordCount];
for (int count = 0; count < wordCount; count++)
wordFrequency[count] = 0;
for(int i = 0; i < wordCount; ++i)
{
j = 0;
encountered = 0;
do
{
if (readInArray[i] == compareArray[j])
encountered = 1;
++j;
} while (j < wordCount);
if (encountered == 0)
{
compareArray[i]=readInArray[i];
wordFrequency[i] += 1;
}
}
for(int k=0; k < wordCount; ++k)
{
cout << "\n" << compareArray[k] << " ";
}
for(int l=0; l < wordCount; ++l)
{
cout << "\n" << wordFrequency[l] << " ";
}
return 0;
}
int readInFile (string tempArray [], string file, int arraySize)
{
ifstream inputFile;
inputFile.open(file.c_str());
if (inputFile)
{
cout << "\nHere is the text file:\n\n";
for(int i=0; i < arraySize; ++i)
{
inputFile >> tempArray[i];
cout << tempArray[i] << " ";
}
inputFile.close();
}
}
Here is my question:
How do you store a word into a dynamically created array when it is first encountered? As you can see from my code made a string array with some of the elements empty. I believe it is suppose to be done using pointers.
Also how do I get rid of the punctuation in the string array? Should it be converted to a c-string first? But then how would I compare the words without converting back to a string array?
Here is a link to a java program that does something similar:
http://math.hws.edu/eck/cs124/javanotes3/c10/ex-10-1-answer.html
Thank you for any help you can offer!!
As to the first part of your question, you are not using a dynamically created array. You are using a regular array. C++ provides implementations of dymnamic arrays, like the vector class http://www.cplusplus.com/reference/vector/vector/
As to the second part of your question, I see no reason to convert it to a c string. The string class in c++ provides functionality for removing and searching for characters. http://www.cplusplus.com/reference/string/string/
The string::erase function can be used to erase punctuation characters found with string::find.
Note: There are other ways of doing this assignment that may be easier (like having an array of structs containing a string and an int, or using a map) but that may defeat the purpose of the assignment.
I'm working on program that counts letters in a piece of text, I can't seem to get it to work. Could someone please point out what I'm doing wrong.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string inputxt;
cout << "enter txt:\n";
getline(cin, inputxt);
char charcheck[ ]={'a', 'b', 'c', 'd'};
int charsize=sizeof(charcheck)/sizeof(char);
int count[charsize];
cout << charsize;
for (int i=0; i==inputxt.length(); i++){
for(int a=0; a==charsize; a++){
if (inputxt[i]==charcheck[a])
++count[a];
}
}
for (int b=0; b==charsize; b++){
cout << "number of " << charcheck[charsize] << ": " << count[charsize];
cout << endl;
}
return 0;
}
Please note I have not put in all the characters to check the text against. Thanks.
for (int i=0; i==inputxt.length(); i++){
The for construct takes 3 parameters:
initialization
continuation condition (and not termination condition like you did). read it as a while ...
loop action (aka. afterthought)
In other words, for (INIT; CONTINUATION; AFTERTHOUGHT) { BODY } is directly translated as:
INIT;
while (CONTINUATION) { BODY; AFTERTHOUGHT; }
Reverse your middle condition, it should be i!=inputxt.length(). The same applies to every other for loops.
In your for loops, you're using == instead of <. For example:
for (int i=0; i==inputxt.length(); i++)
should be:
for (int i=0; i < inputxt.length(); i++)
I tried the code below to return an array with all string ids, but it didn't work.
The output just returns a number. How can I return an array with ids?
#include <iostream>
#include <string>
using namespace std;
string* getArray()
{
int nanim;
cout << "Enter the number of animals: ";
cin >> nanim;
string *id = new string[nanim];
for ( size_t i=0; i < nanim; i++ )
{
cout<< "\nEnter id anim "<< i+1 << ": ";
cin >> id[i];
}
for ( size_t i = 0; i < nanim; i++ )
{
cout << id[i] << endl;
}
return id;
}
int main()
{
int n;
cin>>n;
string* anim[n]=getArray();
cout<<anim;
return 0;
}
You are returning a pointer to the first element in the array.
To access array elements just having called string* arr = getArray(); you can use arr[0], arr[1], arr[2] etc. to access the strings.
Don't forget to delete the memory you allocated in the function though; at the moment you have a big memory leak.
Generally this is not good programming though since the function caller doesn't know how many elements there are in the returned array. It would be better to get the number of animals in the caller and pass that into your function.
Better still, rebuild your code to use std::vector as I see you're already using stl. Then you don't need to worry (explicitly) about memory allocation and deallocation.
You do not need to read the number of elements twice, and the type of the anim should be string*, not string* []. Unfortunately, this wouldn't tell you the number of items in the array, so you need to get it from the getArray, for example, like this:
string* getArray(int& nanim) {
// Remove the declaration of nanim, and keep the rest of the code unchanged
...
}
int main()
{
int n;
string* anim = getArray(n);
for (int i=0; i != n; i++) {
cout << anim[i] << endl;
}
delete[] anim;
return 0;
}
This is not an optimal C++ solution, though: you would be much better off using std::vector instead of an array, because the vector grows dynamically, and its size is returned along with the container itself. There would be no need to delete[] the result either, which would significantly simplify your code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> getVector()
{
int nanim;
cout << "Enter the number of animals: ";
cin >> nanim;
vector<string> res;
for ( size_t i=0; i < nanim; i++ )
{
cout<< "\nEnter id anim "<< i+1 << ": ";
string tmp;
cin >> tmp;
res.push_back(tmp);
}
return res;
}
int main()
{
vector<string> anim = getVector();
for ( size_t i = 0; i < anim.size(); i++ )
{
cout << anim[i] << endl;
}
return 0;
}