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

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)

Related

Integer changes value without changing it in for loop

This kind of explains it all I really don't know why this is happening, can you guys help? I even made the length constant because I though that could be the problem, but it still happens so I really don't know.
So the problem is that I define length1 as 4, but then after a few times in the for loop, the value just randomly changes...
#include <iostream>
#include <string>
using namespace std;
int uppercase[26] = {65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90};
int lowercase[26] = {97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122};
string test;
int entered_text[] = {};
int length = 0;
int length1 = 0;
int main() {
cout << "Enter Text:" << endl;
getline (cin, test);
length = test.size();
length1 = 4;
cout << test<< endl;
for (int i = 0; i < length1; i++){
entered_text[i] = test[i];
}
cout << entered_text[0] << endl;
return 0;
}
By looking at your code, it seems you're approaching this problem as if you were coding in JavaScript and using objects. Obviously, C++ does not approach objects the same way as JavaScript (nowhere near the same).
Here is a rough example of what you could do instead. I don't understand what you're trying to do, but I believe you can implement dynamic arrays and pointers to tackle the problem you have. Read up on using C++ pointers and C++ dynamic arrays. Here is some "rough" code that will hopefully get you on your way:
int main() {
cout << "Enter Text:" << endl;
getline (cin, test);
cout << test<< endl;
length = test.size();
// Create dynamic array and have this array the size of your string.
// Also, initialize a pointer to point to the address of your new array
int *enteredText;
enteredText = new char [length];
int *save = enteredText;
// Iterate over the array “entered_text” and assign it values
for (int i = 0; i < length; i++){
*entered_text = test[i];
entered_text++;
}
// now print chars
for (int i = 0; i < length; i++){
cout << *save << endl;
save++;
}
return 0;
don't make every variable you use global, its better to keep them local if there's no strong reason to do otherwise, and in c++ you have to tell your compiler the size of your array, or use allocation, but I would suggest to use std::vector<int>

How to return an array from a function in c++ [duplicate]

This question already has answers here:
Return array in a function
(20 answers)
Closed 4 years ago.
I'm really confused on the theory behind this. Not sure how to return the array from my isAscending function so i can print out in the main.
#include <iostream>
#include <string>
using namespace std;
// Implement printArray here
void printArray(int array[], int n){
for (int i = 0; i < n; ++i )
cout << array[i] << endl;
};
// Implement isAscending here
int isAscending(int array[], int n){
for(int i = 0; i <= n; ++i){
for(int j = 0; j <= n; ++j){
if(array[i] > array[j+1]){
int temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
return printArray(array, n);
};
// DO NOT CHANGE MAIN FUNCTION BELOW
int main() {
int myarray[100];
cout << "Enter number of integers : ";
int n;
cin >> n;
cout << "Enter " << n << " integers" << endl;
for (int i = 0; i < n; i++)
cin >> myarray[i];
cout << "Contents of array : ";
printArray(myarray, n);
cout << "Output of isAscending: " << isAscending(myarray, n) << endl;
}
Should I use pointers to pass the elements in the array i am stuck.
The short answer is you don't. When you pass an array to a function, you're actually just passing a pointer to the first element (the array decays to a pointer when you pass it as an argument). This means that if you modify the array in the function, you're modifying the original array and not a copy. Therefore, your isAscending() function will bubble sort the array you called it on and it does not need to return anything.
Just a side note, it seems like the assignment simply wants you to check if an array is ascending, instead of sorting it. In that case, isAscending() should return a bool.
If you need a function to return an array, you can't just pass a pointer to the first element since the array goes out of scope as soon as the function returns. You could dynamically allocate the array, but that just creates a bunch of new problems. Another way might be to return the pointer to the first element of the array passed to it as an argument like this, but there isn't much point in doing that since the caller already has access to the array.
The best way would be to use something like std::array or std::vector, which you can return by value just like any other variable. I would also recommend getting a good book.
(I provided this answer besides flagging as a duplicate since I thought the answer of the duplicate question was not complete enough and might mislead someone into trying to return a pointer to a local array)

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?

Method problems: Deleting duplicate chars in an array

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.

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;
}