Method problems: Deleting duplicate chars in an array - c++

So I am trying to delete duplicate chars in a partially filled array. The array is populated from a file located on my PC. My array population method is working fine; however, my duplicate deleting method is not. Here is my method:
void deleteRepeated(char array[], int* numberUsed)
{
for (int x = 0; x < *numberUsed ; x++)
{
cout << "Positions used: " << *numberUsed << endl;
for (int y = x+1; y < *numberUsed; y++ )
{
cout << "Positions used: " << *numberUsed << endl;
if (array[y] == array[x])
{
cout << "Positions used: " << *numberUsed << endl;
for (int z = y; z < *numberUsed; z++)
array[z] = array[z+1];
y--;
*numberUsed--;
cout << "Positions used: " << *numberUsed << endl;
}
}
}
}
I am passing the entire array, and the number of indices used in that array. The array length is 10, and my tests, I am using 6 out of those 10 with the chars: {'g', 'g', 'n', 'o', 'r', 'e'}. What am I doing wrong?
NOTE: "cout << "Positions used: " << *numberUsed << endl" is being used to check if the method is correctly deleting or not. In the most inner loop where index is z, is where the method starts to go bonkers.
Any help would be much appreciated.

(I wrote the first part of this answer before I read your comment about STL not being allowed, but I'll leave it anyways because I think it's rather neat code.)
You could use the functionality that the C++ standard library makes available to you. Use std::string instead of char arrays (that's nearly always a good idea), then you can do the following (note: C++11 only because of unordered_set and std::begin):
#include <string>
#include <unordered_set>
#include <iostream>
#include <iterator>
std::string uniquechars(const std::string& s) {
std::unordered_set<char> uniquechars(std::begin(s), std::end(s));
std::string newstring(std::begin(uniquechars), std::end(uniquechars));
return newstring;
}
int main() {
std::string teststr("thisisanexamplesentence");
std::cout << "The unique characters of " << teststr << " are " << uniquechars(teststr) << std::endl;
}
Note that it doesn't keep the original order of the characters though, so if that's needed this does not work.
If you have to work without the standard library, you have to dig a bit deeper. #TimChild above already made a good start diagnosing what's wrong with your program, but there are more efficient solutions, for example keeping some kind of record of which characters you have already seen. As you're working with chars, I would consider a bit-field that can hold markers (extra overhead of 256/8=32 bytes) or if that's not too much, just a plain array of bools (extra overhead 256 bytes). As the latter is easier to implement and the code is more legible:
void deleteRepeated(char array[], int *numused) {
bool seenthischar[256] = {false};
char *readpointer = &array[0];
char *writepointer = &array[0];
int length = *numused;
for ( ;readpointer <= &array[0] + length; readpointer++) {
if (seenthischar[((unsigned char) *readpointer)]) {
*numused--;
} else {
seenthischar[((unsigned char) *readpointer)] = true;
*writepointer = *readpointer;
writepointer++;
}
}
}
This only has one loop, so it only has to go through the array once, i.e. its time complexity is linear in the length of the input array.

Every time you find a dup you reduce the number chars used
*numberUsed--;
but remember this controlling the first loop index
for (int x = 0; x < *numberUsed ; x++)
so try this
int count =*numberUsed;
for (int x = 0; x < count ; x++)
this way you visit all the original chars in the array.

Related

how to convert an for loop to while loop c++

I'm trying to convert a for loop to while loop in c++ and do some checking for duplicates in a random number generator for generating lotto numbers so far all the stuff i'm trying seems to make the compiler very unhappy and I could really use a few pointers. It's the for loop in the Harray() function that feeds the Balls[] array
that i want to convert to a while loop.
#include<iostream>
#include<cstdlib> // to call rand and srand.
#include<ctime> // to make rand a bit more random with srand(time(0)) as first call.
#include<iomanip> // to manipulate the output with leading 0 where neccesary.
using namespace std;
// Hrand() function create and return a random number.
int Hrand()
{
int num = rand()%45+1; // make and store a random number change 45 for more or less Balls.
return num; // return the random number.
}
// Harray() function create and fill an array with random numbers and some formatting.
void Harray()
{
int Balls[6]; // change the number in Balls[6] and in the for loop for more or less nrs. a row.
for(int x=0; x<=6; x++) //the loop to fill array with random numbers.
{
int a; // made to pass the Balls[x] data into so i can format output.
int m = Hrand(); // calling the Hrand() function and passing it's value in int m.
Balls[x] = m; // throwing it into the array tought i did this because of an error.
a = Balls[x]; // throwing it into int a because of an type error.
cout<<"["<<setfill('0')<<setw(02)<<a<<"]"; //format output with leading 0 if neccesary.
}
cout<<endl; // start new row on new line.
}
// Main function do the thing if compiler swallows the junk.
int main() // start the program.
{
int h; // int to store user cchoice.
srand(time(0)); // make rand more random.
cout<<"How many rows do you want to generate?"<<endl; // ask how many rows?
cin>>h; // store user input.
for(int i=h; h>0; h--) // produce rows from user input choice.
{
Harray(); // calling Harray function into action.
}
return 0; // return zero keep the comipler happy.
}
I would like to always have six diffrent numbers in a row but i don't see how to get there with the for loops i think the while loop is way to go but am open to any suggestion that will work. I'm just starting with c++ i might have overlooked some options.
int x=0;
while(x<6)
{
int a;format output.
int m = Hrand();value in int m.
Balls[x] = m; because of an error.
a = Balls[x];
cout<<"["<<setfill('0')<<setw(02)<<a<<"]";
x++;
}
Here, I also fixed a bug. Since Balls has 6 elements, the last element will be 5. Thus you want x<6 instead of x<=6. That goes for the for loop too.
One drawback of while loops is that you cannot declare local variables with them.
First of all, you should realize that the difference between a for loop and a while loop is mostly syntactic--anything you can do with one, you can also do with the other.
In this case, given what you've stated as your desired output, what you probably really want is something like this:
std::vector<int> numbers;
std::set<int> dupe_tracker;
while (dupe_tracker.size() < 6) {
int i = Hrand();
if (dupe_tracker.insert(i).second)
numbers.push_back(i);
}
The basic idea here is that dupe_tracker keeps a copy of each number you've generated. So, you generate a number, and insert it into the set. That will fail (and return false in retval.second) if the number is already in the set. So, we only add the number to the result vector if it was not already in the set (i.e., if it's unique).
How convert for-loop to while-loop
#include <iostream>
class T545_t
{
// private data attributes
int j;
public:
int exec()
{
// A for-loop has 3 parameters, authors often fill 2 of them with magic
// numbers. (magic numbers are usually discouraged, but are expected
// in for-loops)
// Here, I create names for these 3 for-loop parameters
const int StartNum = 2;
const int EndNum = 7;
const int StrideNum = 2;
std::cout << std::endl << " ";
for (int i = StartNum; i < EndNum; i += StrideNum ) {
std::cout << i << " " << std::flush;
}
std::cout << std::flush;
// A while-loop must use / provide each of these 3 items also, but
// because of the increased code-layout flexibility (compared to
// for-loop), the use of magic numbers should be discouraged.
std::cout << std::endl << " ";
j = StartNum;
do {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
} while(true);
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(true) {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(j < EndNum) {
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::endl;
return 0;
}
}; // class T545_t
int main(int , char** )
{
T545_t t545;
return(t545.exec());
}
Ask me where 'j' is declared?
This code is marked as C++, so in this case, I have declared 'j' in the private data attribute 'section' of this class definition. That is where you'd look for it, right?
If your c++ code does not have class, what's the point?

C++ reversing a string

I'm trying to reverse a string in my C++ code line below revStr.at(j) = str.at(size);
But it doesn't change any of the elements in revStr.
Is there another way to do it without using any libraries.
#include <iostream>
#include<sstream>
#include <iterator>
using namespace std;
int main() {
ostringstream d;
long long c = 123456789;
d << c;
//cout << c << endl;
string str = d.str();
//cout << str.at(0) << endl;
int size = str.size() - 1;
//cout << size << endl;
ostringstream e;
e << str;
string revStr = e.str();
for (int i = size; size==0; size--) {
//cout << str.at(size);
int j = 0;
revStr.at(j) = str.at(size);
j++;
} // End For
cout << "Original String is :" << str << endl;
cout << "Reversed String is :" << revStr << endl;
}
Use std::reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string test{"Hello"};
std::cout << "Original string: " << test << std::endl;
std::reverse(test.begin(), test.end());
std::cout << "Reversed string: " << test << std::endl;
return 0;
}
Output:
Original string: Hello
Reversed string: olleH
If you just want to reverse a string, you should use std::reverse, as described by Tyler Lewis. It is the best option.
If you want to learn C++, then writing your own version is good practice.
The line
for (int i = size; size==0; size--)
means “Create a new int called i and set it to size initially. Then, while size is zero, do the following and then decrement size”.
There are three problems with this:
Size is not zero unless you entered a one-character string
Since you never use i, there’s no point in declaring it
Inside the loop you use j which is set to zero each time.
You can fix the first by changing the middle part of the for loop to size >= 0 (but be careful—if you later change it so that size is an unsigned type, because it doesn’t make sense for it to be negative, that code won’t work; it’s generally better to increment going up instead). You can fix the second by using i everywhere in the loop statement, and not changing size. You can fix the third by using i in the loop body, and not declaring a new variable inside the loop.
I noticed you used std::string so I used std function swap and string. Depending on if you consider this as a 'library'. There are several definitions of 'reverse'. You could reverse the word order in a string, or a pure char to char reversal like I wrote. Reversal could also mean changing character case, etc... but this is simply swap first and last. Then swap the 2nd and 2nd to last, then swap the 3rd and 3rd to last, etc...
So some points from your code. You only need to loop half the string length. The swap is from the ith and the ith to last. So the last is numCharacters - 1, thus the ith to last would be Last - i or numCharacters - 1 - i. I believe this is what you intended by using a farLeft(i) and a farRight(j) index.
#include <iostream>
void reverseStringInPlace(std::string &stringToReverse)
{
int numCharacters = stringToReverse.length();
for (int i=0; i<numCharacters/2; i++)
{ std::swap(stringToReverse[i], stringToReverse[numCharacters-i-1]); }
}
int main()
{
std::string stringToReverse = "reversing a string";
std::cout << stringToReverse << std::endl;
reverseStringInPlace(stringToReverse);
std::cout << stringToReverse << std::endl;
return 0;
}
Output:
reversing a string
gnirts a gnisrever
Changes made to the piece of code in question, it works.
for (unsigned int i = size; size >= 0; size--) {
revStr[j] = str[size];
j++;
}

C++ Passing values to 2D char array in a function

I am trying to use a function to sort through a char array full of words. The current issue I am having is that in my sortNames function I am getting the error, "expression must be a modifiable lvalue" at the part below
hold = nameArr[ii];
nameArr[ii] = nameArr[jj];
nameArr[jj] = hold;
I am guessing that its because I am trying to pass values through an array for some reason. I am struggling with understanding references and pointers and the such, and I imagine that is hurting me here as well. Any help with this would be fantastic, thank you in advance.
Here is my current code...
#include <iostream>
#include <string>
using namespace std;
char nameArr[20][15]; // array to store the 20 values
int val = 0; // variable to pass values to the array
int x = 0; // loop counter outside functions
//Function prototypes
void getNames(char (&nameArr)[20][15], int &val);
void sortNames( char(&nameArr)[20][15]);
//getNames Function
void getNames(char (&nameArr)[20][15], int &val)
{
int i = 0; // loop counter
cout << "Awesome, now lets input those names...\n" << endl;
for (i = 0; i < val; i++)
{
cout << "\nNAME " << i+1 << ": " << ' ';
cin >> nameArr[i];
}
cout << "\n\n\nThese are the names that you inserted:\n" << endl;
for (i = 0; i < val; i++)
{
cout << nameArr[i] << "\n" << endl;
}
}
// sortNames function
void sortNames( char(&nameArr)[20][15])
{
int n = 15; // max length of word
int ii = 0; // loop counter
int jj = 0; // other counter
string hold; // holding array
for (int ii = 0 ; ii < n ; ii++)
{
for (int jj = ii + 1; jj < n; jj++)
{
if (nameArr[ii] > nameArr[jj])
{
hold = nameArr[ii];
nameArr[ii] = nameArr[jj];
nameArr[jj] = hold;
}
}
}
}
int main()
{
cout << "NAME SORTER!\n\nPlease enter in the amount of names you wish to enter: " << ' ';
cin >> val;
getNames(nameArr, val);
cout << "\n\n\nAlright, lets sort now..." << endl;
sortNames(nameArr);
cout << "\nHere are the results:\n" << endl;
for (x = 0; x < val; x++)
{
cout << nameArr[x] << "\n" << endl;
}
system("pause");
}
Your main problem here is that you are trying to use an assignment operator on two fixed sized arrays, which isn't legal. Consider the following code:
int a[2] = {0, 0};
int b[2] = {1, 1};
a = b;
This gives the same error you are getting. On the lines you mentioned, you are doing the same thing with char[15] arrays.
To fix your problems, you either need to allocate your char array dynamically/work with the pointers, or a simpler solution would be to just change your char[][] array to a string[] array.
That being said, there are a lot of things you can clean up here:
You have a few variables declared globally that can just be defined in main or lower
You can declare loop counters inside the for loop instead of beforehand, as you do in the sortNames function
In sortNames you are declaring a few variables twice
I'll add a few things to dwcanilla's answer.
You will want to change your function prototypes and headers to something more like this:
void getNames(char ** & arr, int val);
void sortNames(char ** & arr);
What this means is that the function accepts a reference to an array of c-strings; that is, when you work with the array within the function you are modifying the actual array you passed and not just a copy. Also I think you'd be fine just passing the integer by value for getNames.
Second, global variables are generally a bad idea. Since you can pass the array reference directly to your functions you may want to declare nameArr and your other global variables inside main instead.
Third, in getNames you won't be able to use cin to assign your c-strings directly.
EDIT: This is a better way --
getting console input for Cstrings
Finally, the < operator doesn't work on c-strings the way you're using it in your sort function. Use strcmp() instead (and be sure to include the cstring header):
if(strcmp(arr[ii], arr[jj]) > 0)

Segmentation fault on creating matrices

I was practicing on c++ on some tutorials and I encountered on a tutorial that creates matrices, I wanted something more from it and I modified it, I dont know matrices at all cuz I didnt learn them yet at school but this code below sometimes works sometimes not.
When it doesn't work I usually get: Segmentation fault.
why does this happen ?
before it happened everytime but after i gave a 0 value to variable line and member on the beginning it doesnt happen anymore, but still if I type exc
Line: 10
Member: 9
it gives:
1 1 1 1 1 1 1 1 1
1 2 3 4 5 1 7 8 9
Segmentation fault
and stopes.
Can anyone explain me this ?
thank you !
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int line=0,member=0;
int i,j,matrice[line][member];
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
cout << "\nCreated Matrice: \n" << endl;
for (i=0;i<line;i++)
{
for (j=0;j<member;j++)
{
matrice[i][j]=i*j+1;
cout << setw(5) << matrice[i][j];
}
cout << "\n\n";
}
return 0;
}
int line=0,member=0;
int i,j,matrice[line][member];
This line shouldn't compile. In standard C++,
arrays of 0 size are not allowed
array sizes must be constant expressions
It appears that your compiler allows these as extensions. In any case when you later input line and member your array size doesn't change. You should define your array after you've input these numbers. But the array must be dynamically allocated (better yet, use vectors)
#include <vector>
//...
int line, member;
cin >> line >> member;
vector<vector<int> > matrix(line, vector<int>(member));
or if you don't want to use vector for educational purposes, do this:
int line, member;
int ** matrix;
cin >> line >> member;
matrix = new int*[line];
for(int i = 0; i < line; ++i)
matrix[i] = new int[member];
Don't forget to free the matrix.
for(int i = 0; i < line; ++i)
delete [] matrix[i];
delete [] matrix;
I suggest that you should read a good C++ book
HTH
The matrice array is initialized with a size of [0][0], which are the values of line and member. Since you override the values with the inputted values, the bounds used in the for loops are invalid.
i.e. You are accessing items out of the array's bounds.
You may want to use new to dynamically create arrays, or just use std::vector which resizes itself.
Also, it is not standard, but if your compiler supports it, you can use variable-length arrays. They behave like regular arrays but are allocated using a runtime-computed value :
int line=0,member=0;
int i,j;
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
int matrice[line][member];
You should also check for the inputted values, since C++ does not allows zero-size arrays (And it wouldn't make sense in your program anyway.)
You are using dynamic array without allocating memory using malloc or similar. That is in your line int i,j,matrice[line][member]; is not an array with constant size thus memory should be dynamically allocated. Or use a constant matix size as poster above suggested.
I agree with other comments that using vectors is a much safer way to solve your problem: using arrays directly is definitely error-prone. Of course, if your exercise requires using arrays, then you should use arrays.
Regarding the performance, I have written a small test using g++ on Ubuntu 10.04. Running
g++ --version
I get
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
My test program creates a 100x100 matrix and sets each element to some value. It first has a few declarations:
#include <vector>
#include <iostream>
#include "util.h" // Timer utilities.
#define LINE_COUNT (100) // The number of lines.
#define COL_COUNT (100) // The number of columns.
#define REPETITIONS (100000) // Number of repetitions for each test.
using namespace std;
Then I have the test using vectors:
void use_vectors()
{
int line = LINE_COUNT;
int member = COL_COUNT;
vector<vector<int> > matrix(line, vector<int>(member));
// Set data.
for (int i = 0; i < line; i++)
{
for (int j = 0; j < member; j++)
{
matrix[i][j] = -5;
}
}
}
Then I have a function to perform the same test (create matrix and set values) using arrays:
void use_arrays()
{
int line = LINE_COUNT;
int member = COL_COUNT;
int **matrix;
matrix = new int * [line];
for (int i = 0; i < line; i++)
{
matrix[i] = new int[member];
}
// Set data.
for (int i = 0; i < line; i++)
{
for (int j = 0; j < member; j++)
{
matrix[i][j] = -5;
}
}
for (int i = 0; i < line; ++i)
{
delete [] matrix[i];
}
delete [] matrix;
}
The main program repeats both tests, and records the time needed for each of them. Here is the main program:
main()
{
long int es = 0;
long int eu = 0;
start_timer();
for (int i = 0; i < REPETITIONS; i++)
{
use_vectors();
}
stop_timer();
es = elapsed_sec();
eu = elapsed_usec();
cout << "Vectors needed: " << es << " sec, " << eu << " usec" << endl;
start_timer();
for (int i = 0; i < REPETITIONS; i++)
{
use_arrays();
}
stop_timer();
es = elapsed_sec();
eu = elapsed_usec();
cout << "Arrays needed: " << es << " sec, " << eu << " usec" << endl;
}
The timer functions are based on the library function gettimeofday() (see e.g. http://linux.die.net/man/2/gettimeofday).
The result is the following:
Vectors needed: 24 sec, 624416 usec
Arrays needed: 10 sec, 16970 usec
So it seems that vectors do have some overhead wrt to arrays. Or can I do something to improve the performance of vectors? I checked my benchmark code a few times and it seems to me I got it right.
Anyway, I would by no means advise using arrays just to gain performance unless it really makes a big difference in your application.
You want to allocate memory dynamically.
Then, Use Dynamic allocation like this:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int line=0,member=0;
int i,j;
int **matrice; //Define matrice as a 2D array(a Matrix)
cout << "\nLine: ";
cin >> line;
cout << "Member: ";
cin >> member;
//start of dynamic allocation
matrice=new int*[line];
for (i=0;i<line;i++)
matrice[i]=new int[member];
//End of dynamic allocation
cout << "\nCreated Matrice: \n" << endl;
for (i=0;i<line;i++)
{
for (j=0;j<member;j++)
{
matrice[i][j]=i*j+1;
cout << setw(5) << matrice[i][j];
}
cout << "\n\n";
}
delete[] matrice; //Releasing allocated memory
return 0;
}

I am trying to return a Character Array but, I'm only getting the first letter returned

I'm working on a small little thing here for school. After hours of researching, and a ton of errors and logic reworking I've almost completed my little program here.
I'm trying to take user input, store it into the string, get a character array from the string ( dont ask why, I just have to put this into a character array ), then get the reversed order of the phrase that the user entered. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <String>
#include <cstring>
using namespace std;
using namespace System;
#pragma hdrstop
char* getCharArray(string);
string reversePhrase( int, char* );
void main(void)
{
string sPhrase = "";
int sSize = 0;
string sReversed = "";
char* cPhrase = NULL;
cout << "Welcome to the You Type It & We'll Reverse it! [Version 1.0] " << endl;
cout << "This program will reverse your phrase, and count how many characters are in it!" << endl;
cout << "To begin just enter a phrase." << endl;
cout << "Enter a phrase: ";
getline( cin, sPhrase);
sSize = sPhrase.length();
cout << endl;
cPhrase = getCharArray(sPhrase);
sReversed = reversePhrase( sSize, cPhrase );
cout << sReversed;
system("pause");
}
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
int place = size;
for ( int i = 0; i < size ; i ++ )
{
sReversed.append(1, cPhrase[place]);
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size];
for (int i = 0 ; i < size ; i++)
{
cArray[size] = sPhrase.at(i);
}
return cArray;
}
When I type in "ownage" into the program, this is what I get returned:
It is almost like my Character Array is getting garbage collected before it can use all of the characters. This is probably an easy fix but, I just don't see how I can get around this one.
Try rewriting getCharArray like this
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size+1]; // NOTE
for (int i = 0 ; i < size ; i++)
{
cArray[i] = sPhrase.at(i); // NOTE
}
}
cArray[size]=0; // NOTE
return cArray;
}
Note that the assignment in the loop now uses the index variable. Also, you need to allocate one extra char in the array to set the null terminator for the string and then you need to set it at the end.
You'll also need to think about deallocating the array at some point
The bug is in this line:
cArray[size] = sPhrase.at(i);
That size should be your loop index.
You should probably look at using std::string more, and not poke around with character arrays when there's no need to.
Why use a char array at all? It's not only useless – it complicates the code substantially (the usage of your function is more difficult, and you've forgotten to free the memory allocated by new!). Why not just have the following function:
string reverse(string const& input);
(Passing the argument by const reference instead of by value saves you a copy!)
In fact, implementing the function only takes a single line using the features of the string class (one of its constructors takes two iterators):
string reverse(string const& input) {
return string(input.rbegin(), input.rend());
}
reversePhrase is also not correct. Try something like this:
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
sReversed.resize(size);
int place = size - 1;
for ( int i = 0; i < size ; i ++ )
{
sReversed [i] = cPhrase[place];
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
First, start the array with -1. After that, use a for loop with -1 and increment inside the loop. Then, you can get the first element of the array.