Dynamic Object in c++ doesn't work - c++

#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
class STRING {
private:
char *S[10];
public:
STRING();
void set_str(int n, const char* str1);
char* get_str(int n);
};
STRING :: STRING(){
for (int i=0; (i < 9); i ++ ){
S[i] = '\0';
cout << S[i];
}
}
void STRING :: set_str(int n,const char*str1) {
S[n] = (char*)malloc(strlen(str1 + 1));
strcpy(S[n], str1);
cout << S[n];
}
char* STRING :: get_str(int n){
return S[n];
}
int main () {
cout << " Init \n";
STRING* str = new STRING();
cout << "Error \n";
return 0;
This program compiles successfully, runs, but when it runs it only works before the inicialization of object STRING* str = new STRING();. So I can't see in this case Error message. Could someone point me my mistake, please?
And if there is a better way to initialize the array of strings, I would be happy to know.
My goal is to initialize tha array of stings. And initially set values of the whole array to NULL.
Regards

Assuming STRING means "a collection of 10 strings", then it's your constructor. You are setting the pointers to the value of the character '\0' and not to a null pointer. You're assigning a char type to a char* type. Now that may work, but then you have the cout statement. And it tries to DEREFERENCE the pointer. But the pointer is pointing to wherever in memory '\0' is, not a null character at that point.
Edit: In response to the OP's question, here's how I think it should be done for initializing to 10 empty char arrays. Your constructor will change to:
STRING :: STRING(){
for (int i=0; i < 10; i ++ ){ // changed to 10. 9 would miss the 10th element
S[i] = new char[1]; // Length-1 char array
S[i][0] = 0; // or '/0' or whatever
cout << S[i]; // Prints nothing
}
}
Also you need a destructor to free the memory:
STRING::STRING~()
{
for(int i = 0; i < 10; i++) {
delete [] S[i];
}
And change your "set" method to use "new" and not "malloc". Or everything to malloc and free. But don't mix them. And remember to use "array delete" and not just delete.
And FTLOG, go to and bookmark this link. Use the built-in string class.

The correct declaration of the member should be:
char S[10];
The way you have it
char *S[10];
declares an array of 10 char *. So when you do S[i] = '\0';, you're initializing S[i], which is a pointer to a char, to '\0', which is probably NULL, so you're basically calling cout << NULL on the next line.

Related

Passing structure by reference and assign string

Here is a simple program where I am trying to pass a structure to a function by reference and a string. The function is supposed to detect the length of the string and assign it a member of the structure. Here is the program:
#include <iostream>
#include <string.h>
struct stringy // structure definition
{
char *str;
int ct;
};
void set(stringy &beany, const char *testing); // function definition
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing); // function call
return 0;
}
void set(stringy &beany, const char *testing) // function prototype
{
int i=0;
while (*(testing+i) != '\0') // this loop counts the number of characters
{
i++;
std::cout << i << "\n";
}
beany.str = new char[i]; // dynamic storage allocation
std::cout << strlen(beany.str); // printing the length of the string
}
For some reason the output of the last line in the function set() is 47 while the value of "i" is 33. The last 15 bytes are filled with garbage value. I want that the length of beany.str should be equal to the length of *testing.
You allocate memory for beany.str but you don't initialize that memory. The contents of the allocated memory, without any initialization, is indeterminate (and in practice will be seemingly random).
Also don't forget that old C-style strings needs to be terminated by the special '\0' character (or functions like strlen will not work).
Both of these problems, using uninitialized memory and forgetting the terminator, will lead to undefined behavior.
beany.str = new char[i]; // dynamic storage allocation
std::cout << strlen(beany.str); // printing the length of the string
strlen looks for the terminating null character '\0'. There is no guaranteed one in beany.str, because you assign it the result of new char[i], which does not zero-initialize the elements. It allocates space for i characters that are not initialized to zero.
Even if they were, strlen would return 0, because it would immediately find '\0' at the first position. If you don't somehow remember i yourself, the size information will be lost.
Look at the output of the following program:
#include <iostream>
int main()
{
char *str = new char[100];
for (int i = 0; i < 100; ++i)
{
std::cout << str[i] << "\n";
}
}
The behaviour is undefined. What you will probably see are some seemingly random characters.
If you want zero-initialization, use new char[i]().
But still, strlen will be 0:
#include <iostream>
#include <string.h>
int main()
{
char *str = new char[100]();
for (int i = 0; i < 100; ++i)
{
std::cout << str[i] << "\n";
}
std::cout << strlen(str) << "\n";
}
You should just get rid of array-new and array-delete. Use std::string.

How to modify array that pointer points to

I need to pass a char pointer to function, then change the value that it points to inside the function and print values outside the function.
The problem I have is that I'm losing it when I leave function and try to print it outside. What can I do to avoid this?
This is an code example:
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
cout << (pText);
cout should print
moob adaB
When I print inside the function, everything is fine(it prints reversed).
My task is to print It out outside the function (as you can see in a 4th line of code)
This is the full of code which have the bug (printing inside func works, outside didn't work)
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
char reverseText(char *text);
int main(){
char array[] = "Bada boom";
char *pTekst = array;
reverseText(pTekst);
cout << (pTekst); //in here it doesn't work
}
char reverseText(char *text){
char befRev[100]; int lenght=-1;
/*until *text doesn't meet '\0' */
for(int i=0;*text!='\0';i++){
befRev[i]=(*text);
text++;
lenght++;
}
/*reversing*/
int j=0;
for(int i=lenght;i>=0;i--){
*(text+j)=befRev[i];
j++;
}
for(int i=0;i<=lenght;i++) //in here it does print the right value
cout << text[i];
};
Just re-arrange the array in-place. The pointer itself doesn't need to change:
#include <cstring>
#include <algorithm>
void reverseText(char* array)
{
auto len = std::strlen(array);
std::reverse(array, array+len);
}
int main()
{
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText << std::endl;
}
Output:
moob adaB
If you really wanted to provide a pointer that points to a different address to the caller, you could simply return it:
char* foo(char* stuff)
{
char* tmp = ....;
...
// do some stuff
...
return tmp;
}
Alternatively, you could pass the pointer by reference, but the intent is less clear than in the previous version:
void foo(char*& stuff)
{
stuff = something_else;
}
But in both cases, you must make absolutely sure the thing the new pointer points to is valid outside of the function. This might require some dynamic memory allocation. For your case, it seems the best and simplest option is to re-arrange the array in place.
To answer your question, you have an error in logic. Notice that in your first loop in reverseText you increment the local pointer text. In your second loop you did not reset text to it's original value so beforeRev is being copied over starting at location text+offset.
If you were to look at pText on return from call to reverseText you would find it contains:
"Bada boom\0moob adaB"
Your reverseText should be renamed palindrome :)
This is pretty straightforward. Some points to note:
An array decays to a pointer when you pass it to a function.
You are passing in a null terminated string. So the length of the char array you are passing in is the length of the string (including white space) +1.
Because you are using a pointer there is no need to assign a temp variable to hold everything.
Here is some code in C that is easy to translate to C++. Working out the actual reverse algorithm is left for you as an exercise.
#include<stdio.h>
void reverseText(char* text)
{
// Hint: It can be done in one loop!
int i;
for(i = 0; i < 9; i++)
{
// Your algorithm to reverse the text. I'm not doing it for you! ;)
*(text + i) = 'r';
}
}
int main()
{
char array[] = "Bada boom";
reverseText(array);
printf("The text reversed: %s\n", array);
return 0;
}
My final code:
#include <iostream>
void reverseText(char* text){
int length=-1; char tmp;
/*Length = sign from 0 to 8 without counting explicit NUL terminator*/
for(int i=0;*(text+i)!='\0';i++){
length++;
}
int j=0; int i=length;
while(j<i){
tmp=*(text+j); //tmp=first
*(text+j)=*(text+i); //first=last
*(text+i)=tmp; //last=tmp
j++;
i--;
}
}
int main(){
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText;
}
I should have read more about pointers before I started this exercise.
You can either return a pointer or pass a pointer to pointer as a function argument.
//pointer to pointer
void reverseText(char** textPtr) {
char* newText = ...; //initialize;
...
*textPtr = newText; //assign newText
}
//return pointer
char* reverseText(char* text) {
char* newText = ...; //initialize
return newText;
}
Remember that if you allocate memory in this function you must do it dynamically (with new or malloc) and you have to free it afterwards (with delete or free respectively). Memory allocation in a function like this is probably a bad practice and should be avoided.

Delete repeated characters from a random word

I'm making a class to delete repeated character from a random word. For example if the input is "aabbccddeeff", it should output "abcdef". However my output contains strange characters after "abcdef". The main.cpp file already exists as the requirements for creating the class. Please see the following codes:
main.ccp
#include <iostream>
#include "repeatdeletion.h"
using namespace std;
int main()
{
char* noRepeats;
int length;
string s;
cout<<"Enter a random word with repeating characters: ";
cin>>s;
RepeatDeletion d;
length=s.length();
noRepeats=d.deleteRepeats(s, length);
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
delete [] noRepeats;
noRepeats=NULL;
return 0;
}
repeatdeletion.h
#ifndef REPEATDELETION_H
#define REPEATDELETION_H
#include <iostream>
using namespace std;
class RepeatDeletion
{
char* c;
char arr[128]={};
bool repeated;
bool isRepeated(char);
public:
RepeatDeletion();
~RepeatDeletion();
char* deleteRepeats(string, int);
};
#endif // REPEATDELETION_H
repeatdeletion.cpp
#include "repeatdeletion.h"
RepeatDeletion::RepeatDeletion()
{
repeated=false;
}
RepeatDeletion::~RepeatDeletion()
{
delete [] c;
c=NULL;
}
bool RepeatDeletion::isRepeated(char c){
bool repeated=false;
if (arr[c]>=1){
repeated=true;
arr[c]++;
}else{
arr[c]++;
}
return repeated;
}
char* RepeatDeletion::deleteRepeats(string str, int len){
c=new char[len];
int j=0;
for (int i=0; i<len; i++){
if (isRepeated(str[i])==false){
c[j]=str[i];
j++;
}
}
return c;
}
Your return character array is not null terminated.
The length function of string does not include \0.
You have two choices
Add null at the end of returned character array, and std::cout the char array directly (instead of char by char)
Output the final length of your char array, and use that as range to print it char by char
Your printing loop loops using the old and unmodified string length. That means you will go outside the characters you added to memory returned by deleteRepeats.
The easiest solution to handle this is to terminate the data as a proper string, and check for the terminator in the loop.
If you want to use a C-string array, they have a null terminator at the end. That means you'll want to (in deleteRepeats) define your character array one character larger than the length:
c=new char[len+1];
And, after the for loop, ensure you put that null terminator in:
c[j] = '\0';
Then, in your calling function, you can just do:
cout << noRepeats;
Even if you don't want to use C strings, you'll need to communicate the new length back to the caller somehow (currently, you're using the original length). The easiest way to do that is (IMNSHO) still using a C-style string and using strlen to get the new length (a).
Otherwise, you're going to need something like a reference parameter for the new length, populated by the function and used by the caller.
(a) But I'd suggest rethinking the way you do things. If you want to be a C++ coder, be a C++ coder. In other words, use std::string for strings since it avoids the vast majority of problems people seem to have with C strings.
That's because in your code you write the following:
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
Here, length refers to the length of the original string (which you, by the way shouldn't pass to your deleteRepeats method). I would suggest you make deleteRepeats return a string and write something like this:
std::string noRepeats = d.deleteRepeats(s);
std::cout << "Your word without any repeating characters: ";
std::cout << noRepeats << std::endl;
C-style string (char *, if you insist) follow the convention that the last character is '\0', indicating that the string ends. You could also change deleteRepeats by appending '\0', i.e.
char* RepeatDeletion::deleteRepeats(string str){
c = new char[str.size() + 1];
int j = 0;
for (int i = 0; i < str.size(); i++){
if(isRepeated(str[i]) == false){
c[j] = str[i];
j++;
}
}
c[j] = '\0';
return c;
}
and in your main
std::cout << noRepeats << std::endl;
instead of the for loop. But really, you should use std::string, and if possible not mix it with char *. Hope that helps.
for(k=0;k<length;k++)
Here length should be the exact length of noRepeats, but not of s
so :
char* RepeatDeletion::deleteRepeats(string str, int len)
should return the length-after too
use std::unique it does what you want:
std::string s{};
std::cin>>s;
auto it = std::unique(std::begin(s), std::end(s));
s.resize(std::distance(std::begin(s),it));
std::cout << s;
the way it works is to go through the range begin to end and move all the remaining elements forward if the current element is equal to the next. It returns the position of the end of the new string (it in this example) but does not actually shorten the string so on the next line we shorten the string to the length equal to the distance of begin() to it.
see live at http://ideone.com/0CeaHW

Segmentation fault from calling a function from an object within an array

I have a programming assignment that requires us to use a dynamically allocated two-dimensional char array in-lieu of strings and vectors. I have two classes: Word which holds a pointer to a char array, and WordList which holds a pointer to a Word array.
The segmentation fault comes from this section of code:
for(int i=0; i<listLength; i++)
fout << "Word " << i << (wordList[i])->getWord() << endl;
where fout is an ofstream object, wordList is a Word** object, and getWord() is a member function of a Word object. The thing is that I use the same wordList[i]->getWord() syntax in another member function of WordList and get the proper output.
Please let me know if more code is needed to properly diagnose the problem
More code:
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include "Word.h"
using namespace std;
class WordList
{
public:
int listLength_;
Word** wordList_;
WordList()
{
char blank = ' ';
char* blankPtr = &blank;
setListLength(1);
wordList_ = new Word* [listLength_];
for(int i=0; i<listLength_; i++)
{
wordList_[i] = new Word(blankPtr);
}
}
void addWord(Word* word, Word** wordList, int n)
{
Word** wl_temp = new Word* [n+1];
for(int i=0; i<n; i++)
{
wl_temp[i] = wordList[i];
}
wl_temp[n] = word;
delete[] wordList;
setWordList(wl_temp);
listLength_++;
cout << " " << (wordList_[n]->getWord()); //works here
}
void parse(const char* filename)
{
ifstream fin(filename);
char end;
char* tw;
while(fin >> end)
{
fin.unget();
fin.get(tw=new char[49], 49, ' ');
Word* w = new Word(tw);
addWord(w, getWordList(), getListLength());
delete w;
delete[] tw;
}
}
void output(const char* outfile)
{
ofstream fout(outfile);
for(int i=1; i<=listLength_; i++)
fout << "Word " << i << (wordList_[i])->getWord() << endl; //not here
fout.close();
}
};
int main(int argc, char* argv[])
{
WordList wordList;
wordList.parse(argv[1]);
wordList.output(argv[2]);
return 1;
}
In WordList::Wordlist:
wordList_[i] = new Word(blankPtr);
You're passing a pointer to a local variable here.
Not only is that a problem in itself, but the "string" isn't zero-terminated.
Regardless of whether Word assumed ownership of the object, this will cause undefined behaviour.
If Word::Word copies its argument, this is a very roundabout (and wrong) way to write new Word(" ").
In parse:
Word* w = new Word(tw);
addWord(w, getWordList(), getListLength());
delete w;
You added w to the word list. Now you're deleteing it.
The word list now contains a pointer to released memory.
Dereferencing it also causes undefined behaviour.
delete[] tw;
This is only OK if Word::Word copies its argument. Otherwise it now holds a pointer you aren't allowed to use for anything.
If you're going to work with hand-rolled allocation and raw pointers, you need to set a very clear policy for which object owns which memory and is responsible for allocating and releasing it.
The best time to do this is before you touch the keyboard.
Note that blankPtr in the constructor points to a local variable, this pointer will not be valid once the constructor returns. Also, in the parse function you delete the pointer to the string, making that pointer invalid as well. Not only that, you actually delete the Word object pointer, meaning you have now have an illegal pointer in your array.
Unless you create a copy (not just copy the pointer, but allocate new memory) inside the Word constructor, your Word objects will contain illegal pointers leading to undefined behavior.
Undefined behavior is tricky, since it can seem to work one time, but not another.

I get a number 2 when I reverse my string

I wrote this code to reverse strings. It works well, but when I enter short strings like "american beauty," it actually prints "ytuaeb nacirema2." This is my code. I would like to know what is wrong with my code that prints a random 2 at the end of the string. Thanks
// This program prompts the user to enter a string and displays it backwards.
#include <iostream>
#include <cstdlib>
using namespace std;
void printBackwards(char *strPtr); // Function prototype
int main() {
const int SIZE = 50;
char userString[SIZE];
char *strPtr;
cout << "Please enter a string (up to 49 characters)";
cin.getline(userString, SIZE);
printBackwards(userString);
}
//**************************************************************
// Definition of printBackwards. This function receives a *
// pointer to character and inverts the order of the characters*
// within it. *
//**************************************************************
void printBackwards(char *strPtr) {
const int SIZE = 50;
int length = 0;
char stringInverted[SIZE];
int count = 0;
char *strPtr1 = 0;
int stringSize;
int i = 0;
int sum = 0;
while (*strPtr != '\0') {
strPtr++; // Set the pointer at the end of the string.
sum++; // Add to sum.
}
strPtr--;
// Save the contents of strPtr on stringInverted on inverted order
while (count < sum) {
stringInverted[count] = *strPtr;
strPtr--;
count++;
}
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
cout << stringInverted << endl;
}
Thanks.
Your null termination is wrong. You're using == instead of =. You need to change:
stringInverted[count] == '\0';
into
stringInverted[count] = '\0';
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
Should use = here.
What is wrong with your code is that you do not even use strlen for counting the length of the string and you use fixed size strings (no malloc, or, gasp new[]), or the std::string (this is C++)! Even in plain C, not using strlen is always wrong because it is hand-optimized for the processor. What is worst, you have allocated the string to be returned (stringInverted) from the stack frame, which means when the function exits, the pointer is invalid and any time the code "works" is purely accidental.
To reverse a string on c++ you do this:
#include <iostream>
#include <string>
int main() {
std::string s = "asdfasdf";
std::string reversed (s.rbegin(), s.rend());
std::cout << reversed << std::endl;
}
To reverse a string in C99 you do this:
char *reverse(const char *string) {
int length = strlen(string);
char *rv = (char*)malloc(length + 1);
char *end = rv + length;
*end-- = 0;
for ( ; end >= rv; end --, string ++) {
*end = *string;
}
return rv;
}
and remember to free the returned pointer after use. All other answers so far are blatantly wrong :)