error : expression must be a modifiable lvalue - c++

I'm getting an error:
expression must be a modifiable lvalue at line, obj.name = ptr->name
I have tried to make obj an array type object like so
for(int j=0 ;j<1;j++)
{
obj[j].id = ptr->id;
obj[j].balance= ptr->balance;
obj[j].name = ptr->name; //still getting error here.
obj[j].nic = ptr->nic;
}
return(obj);
}
but that has not worked either.
if i comment the error out and pass just three remaining values it should work but i receive garbage values after the first out put.
here is the original code:
#include<iostream>
using namespace std;
struct bank
{
int id, nic;
float balance;
char name[20];
};
bank search(bank* );
void main()
{
bank data[2],mobj;
for(int i=0;i<2;i++)
{
cout<<"enter name: ";
cin>>data[i].name;
cout<<"enter id: ";
cin>>data[i].id;
cout<<"enter balance : ";
cin>>data[i].balance;
cout<<"enter nic : ";
cin>>data[i].nic;
}
mobj=search(data);
cout <<"balance of customer no. "<<mobj.balance<<endl;
cout<<"id is" <<mobj.id<<endl;
cout<< "nic is"<<mobj.nic<<endl;
system("pause");
}
bank search(bank *ptr)
{
int id;
cout<<"enter value you want to serch"<<endl;
cin>>id;
bank obj;
for(int i=0 ; i<2 ;i++)
{
if(ptr->id == id)
{
break;
}
ptr++;
}
obj.id = ptr->id;
obj.balance= ptr->balance;
obj.name = ptr->name; //error in this line(obj must be modifiable value)
obj.nic = ptr->nic;
return(obj);
}
please help as you see fit!

obj.name is an array of char. You cannot do assignments on arrays. So if you want to stick to arrays:
see c++ array assignment of multiple values
use strcpy(obj.name, ptr->name);
but I'd recommend to convert to std::string ... it's much easier to work with than arrays and it seems to me you plan to use obj.name as string. So got with the proper strings.

Your options are:
Have name as a std::string. Then it will work
use strcpy( obj.name, ptr->name );
If your code is C++ then the first has even more advantages that when you read it in with cin it will automatically ensure that the buffer is big enough for what the user enters.
Try entering a name of 20 or more characters now and see what happens. You will have undefined behaviour and your program may crash.
Those are the fixes anyway.
The reason your code does not work is that an array is not assignable. It is not an l-value. It is the start of a fixed array of bytes. I know it is confusing because you can use = to initialise it thus you can do:
char name[20] = "Frank Smith"; // legal. This is initialisation
but you can't do:
char name[20];
name = "Frank Smith"; // error. This is attempted assignment.
With std::string it works as string is a class in the standard library. (Actually the class is basic_string< char, char_traits<char>, allocator<char> > but assume it is a class for now). And it has methods that know how to assign to it, stream into it, etc. and manage the memory properly.
The only time the array in your struct is more useful is if you want to store it to disk or send it over a connection where you need "raw" data, or where you want to interface it with "C" or a scripting language that works with C structs.

obj[j].name is an array. You can't copy an array like that.

Related

C++ storing an element of a string array into a variable

I am currently coding in C++ and am fairly new to it. I am running into issues with converting an element of an array of strings into a variable. The cout statement dcity[selection-1] works as intended. However, I am unable to store dcity[selection-1] into a variable named departureLocation. Visual Studios gives me the error that there is no suitable conversion function from a string to a char. Does anyone have advice on how to properly store this? Thanks!
int main()
{
int selection = 0;
char departureLocation;
std::string dcity[] = { "Seattle Detroit Seattle Chicago Houston Seattle" };
std::cout << "Please choose a number from the list";
std::cin >> selection;
std::cout << dcity[selection-1];
departureLocation=dcity[selection-1]
};
Since C++ is a strongly-typed language, it doesn't like type mismatches.
You've declare your variable in the following way:
char departureLocation;
This means departureLocation is a variable of type char, or a single character. So 'C' can go into departureLocation but "Chicago" cannot, as it is more that one character.
You've also declared your array like so:
std::string dcity[] =
Here, you have defined the type of the array as std::string. So elements of the array are strings, not chars.
The short answer is that you need to change the type of departureLocation to a string when you declare it, instead of a char. Something like:
std::string departureLocation;
I also didn't see any include statements in your code above. For C++ to recognize the string class, you'll need to make sure the following is at the top of your code somewhere:
#include <string>
dcity is an array of std::strings. departureLocation is a char which can only hold one character. To store (copy) an element of the array dcity, departureLocation must be of type std::string (or any other type that can be constructed fron a std::string):
std::string dcity[] = { "Seattle Detroit Seattle Chicago Houston Seattle" };
std::string departureLocation = dcity[0];
Be aware thet dcity is an array consisting of only one element. Maybe you want an array where each city is a seperate array element:
std::string dcity[] = { "Seattle", "Detroit", "Seattle",
"Chicago", "Houston", "Seattle" };
std::string departureLocation = dcity[2];
std::cin >> selection;
std::cout << dcity[selection-1];
Also you should do some error checking before using user input as an array index:
if (!(std::cin >> selection) || selection < 1 || selection > sizeof(dcity) / sizeof(*dcity)) {
std::cerr << "Input error!\n";
return EXIT_FAILURE;
}
std::string departureLocation = dcity[selection - 1];
If you don't need independent copies of your array elements you could also use a reference to std::string:
std::string &departureLocation = dcity[selection - 1];
Be aware that changes to the string using departureLocation will now reflect on the array element departureLocation references. If you don't want to allow changes, use a const reference:
std::string const &departureLocation = dcity[selection - 1];
First of all the compiler thinks that there is only one element in the array because arrays in c++ should have commas between each element and each string must be enclosed inside double quotes.The second error is that you are trying to save data of type string into a variable having data type char.
Code
#include<string>
#include<iostream>
using namespace std;
int main()
{
int selection=0;
string depaturelocation;
string dcity[]={"Seattle","Detroit","Seattle","Chicago","Houstan","Seattle"};
int size=sizeof(dcity)/sizeof(dcity[0]);
for(int i=0;i<size;i++)
{
cout<<i+1<<" : "<<dcity[i]<<endl;
}
cout<<"please enter the destination no:";
cin>>selection;
for(int i=0;i<size;i++)
{
if(selection-1==i)
{
depaturelocation=dcity[i];
}
}
cout<<"destination:"<<depaturelocation;
return 0;
}
Your code needs little modification.
1. An array is initialized by giving its component values separated by a comma. Note each individual element should be of the same type as that of the declared array.
2. The C++ is very strict with the type matching. We can assign objects only of the same type. In the above code, a string object is being assigned to a character variable which is against the rule. A C string is an array of characters terminated by null character (\0). In C++, string is more advanced and it is an object which has very useful member function. For e.g. to get length of the string, just say obj.length(). We need to have character array since in string there can be more than one char element. We need to have c-string of the string object to get into an array of characters. Please see below the modified code.
#include <iostream>
#include <cstring>
#include <string>
using namespace std; //std:: is not required in front of cout
int main()
{
int selection = 0;
string dcity[] = { "Seattle", "Detroit" ,"Seattle", "Chicago", "Houston","Seattle" };
cout << "Please choose a number from the list";
cin >> selection;
cout << dcity[selection-1] << endl;
char departureLocation[dcity[selection-1].length()+1];
strcpy(departureLocation,dcity[selection-1].c_str());
cout << departureLocation;
// cout << *c;
return 0;
}
You could to store the selection in a std::string, because char can only store a single character. Be also careful of where you access your array to not go out of bounds (what happens if somebody enters 1000 etc.) and that non-programmer users index lists starting with 1. You can try this code:
#include <iostream>
#include <string>
int main()
{
const auto Cities = { "Seattle", "Detroit", "Seattle", "Chicago", "Houston", "Seattle" };
std::cout << "Please choose a number from the list (1-" << Cities.size() << "): ";
int selection = 0;
std::cin >> selection;
if (selection < 1 || selection > Cities.size()) {
std::cout << "\ninvalid selection!\n";
return -1;
}
const std::string departureLocation = *(Cities.begin() + selection - 1);
std::cout << "\nyou selected: " << departureLocation;
return 0;
};

compiler adding random characters to my char array

I have a function called SearchArray() which calls another function called SearchRecords(char StudentNo[]) to check the database array of gRecs for a match in student numbers.
When i run the debugger the value of StudentNo is being shown as StudentNo = 0x22fde0 "12345678" if StudentNum = "12345678".
What are these additional characters?
SearchArray() function
void SearchArray(){
char studentNum[8];
cout << "Enter student number: ";
cin >> studentNum;
char i = SearchRecords(studentNum);
if (gRecs[i].studentNumber != studentNum){
cout << "Record not found" << endl;
}
else {
PrintRecord(i);
}
}
SearchRecords() function
int SearchRecords(char StudentNo[])
{
for (int i = 0; i < gNumRecs; i++){
if(gRecs[i].studentNumber == StudentNo)
{
return i;
}
}
return -1; //not found
}
Do you mean the "0x22fde0"? Those aren't in your character array, your character array only contains the part in quotes ("12345678"). The hexadecimal number 0x22fde0 is the address of the first character. In C/C++, any array is really just a pointer to the first element: the value of the variable is the address of the first element. So the debugger is showing you that address value. But it also knows that character arrays usually store strings, so it is also helpfully showing you the contents of that array as a string.
As this comment notes, you're comparing pointers not strings. You'll save yourself many headaches by changing your studentNumber type to std::string. This will allow you to use comparison operators(==,!=,<,<=,>,>=) with either a std::string or a raw string(char*) on the right side. I highly recommend reading up on strings at tutorialspoint.com and cplusplus.com.
When posting in the future, please post any relevant custom data structures(such as the layout of your gRecs element type), it helps us solve the problem faster.

passing array as parameter to a function

this script is supposed to output array values that were inputted by the user into array "store." I am trying to store all the char array values into string temp. I get the error on line 12: "[Error] invalid conversion from 'char*' to 'char' [-fpermissive]." Would appreciate any help!
Edit: so I fixed the declaration and now at least it compiles, but the answer I get on my cmd is all jumbled up. Why is this so? The cmd only correctly couts the first string but after the space, it messes up.
#include <iostream>
#include <cstdlib>
using namespace std;
void coutArray(char[], int);
int main()
{
char store[50];
cout << "enter text: " << endl;
cin >> store;
coutArray(store, 50);
system("pause");
return 0;
}
void coutArray(char store[], int max)
{
string temp = "";
int i = 0;
while (i < max)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
Using input from all answerers I finally got the fixed code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
void coutArray(char[], int);
int main()
{
char store[50] = {0};
cout << "enter text: " << endl;
cin.getline(store, 50);
coutArray(store, 50);
system("pause");
return 0;
}
void coutArray(char store[], int max)
{
string temp = "";
int i = 0;
while (i < max && store[i]!=0)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
Thanks everyone. i learned a lot!!!
When you get an input using "cin" your input automatically ends with 0 (NULL).
You just need to add one little piece of code to your while statement.
instead of this :
while (i < max)
use this :
while (i < max && store[i]!=0)
Now it will stop when the input string is finished and won't print any garbage existed in the array beforehand.
To show that cin does add terminating zero, i initialized the array to 46, and put a breakpoint after the cin
so I fixed the declaration and now at least it compiles, but the answer I get on my cmd is all jumbled up. Why is this so?
Not sure what you mean by jumbled up. But since you did not tell us what you typed its hard to know it looks like it worked to me:
> ./a.out
enter text:
Plop
Plop�ȏU�
Notice that since my input is only 4 characters long. This means that a lot of the characters in the array still have undefined (ie random values). This is why I am seeing junk. To get past this initialize the array to have all 0 values.
char store[50] = {0};
Even bettern use a C++ object than handles longer strings.
std::string store;
std::getline(std::cin, store);
Note: passing arrays to functions by value is not a good idea. On the other end they have decayed to pointers and thus do not act like arrays anymore (they act like pointers whose semantics are similar but not identical).
If you must pass an array pass it by reference. But I would use a C++ container and pass that by reference (it is much safer than using C constructs). Have a look at std::string
The declaration of the function is wrong. Should be void coutArray(char *, int);
Look at the Implicit Conversion rules to understand what the compiler can do and what it cannot to do for you.
The issue with your program was that you were probably entering in less characters than the maximum size of the buffer. Then when you passed the maximum size as the parameter to coutArray, you assigned unfilled slots in the char array to temp. These unfilled slots could contain anything, as you have not filled them up to that point.
Your program is still correct, but what would be better would be to use read so that the number of bytes you specify is the minimum number of bytes that can be entered:
std::cin.read(store, 50);
Even better solution would be to use std::string:
std::string store;
std::cin >> store;
// or for the entire line
std::getline(std::cin, store);
It also follows that your coutArray should be changed to:
void coutArray(std::string);
// ...
void coutArray(std::string str)
{
std::cout << str << std::endl;
}
Look at this way
template<typename T, size_t N>
void MyMethod(T (&myArray)[N])
{
//N is number of elements, myArray is the array
std::cout<<"array elements number = "<<N<<endl;
//put your code
string temp;
temp.resize(N+1);//this is for performance not to copy it each time you use += operator
int i = 0;
while (i < max)
{
temp += store[i];
i++;
}
cout << temp << endl;
}
//call it like this
char arr[] = "hello world";
MyMethod(arr);

cin and char array pointer in struct

As a c++ beginner I've written the following code:
int main(void){
struct car{
char * make[200];
int manfYear;
};
int num=0;
cout << "How many cars do you wish to catalogue? ";
cin >> num;
car * Cars = new car [num];
for (int i=1;i<=num;i++){
cout << "Car #" << i << ":" << endl << "Please enter the make: ";
cin.getline(*Cars->make,200);
cout << "Please enter the year made: ";
cin >> Cars->manfYear;
}
My problem is that I can't get my head round a problem where I get a segfault when running the program at the point I need to enter the model of the car. Can someone please explain what I'm doing wrong?
As far as I understand it I'm passing a pointer to the array "make" which should make it work. Is my understanding way off?
Thanks in advance
Dan
Four issues I see right away:
Issue 1
In your struct, you have:
char * make[200];
In English, this is saying, "create an array of 200 pointers to character", when I think you want to say, "create an array of 200 characters." So you should have instead:
char make[200].
Issue 2
You are looping by starting at 1. This will skip the first car in the array - remember arrays are zero-indexed. So you should have instead:
for (int i = 0 ; i < num ; i++)
and for display purposes, you could say:
cout << "Car #" << (i+1) << ":" << endl << "Please enter the make: ";
Issue 3
Where you say:
cin.getline(*Cars->make,200);
and
cin >> Cars->manfYear;
Where in these lines are you specifying which car the user is populating? Nowhere. If you are looping with i, then you need to actually mention i. These should work:
cin.getline(Cars[i].make,200);
and
cin >> Cars[i].manfYear;
Notice that we are using ., not ->. This is because the items in the Cars array are actual instances, not pointers. The Cars array is itself a pointer, but not its contents.
Issue 4
All credit to #Ben C who pointed this out first: mixing the >> operator with getline() function on cin can lead to strange behavior, with leftover CR's from >> going into the getline() call. You could use either all >> (disadvantage: you don't have the 200 limit enforced when reading the make) or all cin.getline() (disadvantage: you will have to use string buffers and then convert them for number of cars and year), or put cin.ignore() after each invocation of >>, like so:
cin >> num;
cin.ignore();
and
cin >> Cars[i].manfYear;
cin.ignore();
Again, all credit to #Ben C for noticing this first.
Last But Not Least
By convention, classes/structs have capital names, and variables have lowercase / camelcase names. Consider renaming the struct from car to Car, and the array from Cars to cars. In other words, the reverse of the capitalization you have right now.
Finally, I concur with all the other posters here: you should consider using string instead of char arrays.
First, use string instead of poor old C char[].
Next: you don't want char * make[200];. You want char make[200];. char * make[200] is an array of 200 pointers to chars, which can be used as 200 null-terminated strings - but then, you would have to new[] each of them. Just use char make[200]; and cin.getline(Cars->make, 200);.
char * make[200] declares an array of 200 pointers; I'm guessing this isn't what you're after.
If you're simply looking to store a string, I'd recommend taking a look at the C++ string type instead.
#include <iostream>
#include <string>
int main()
{
using namespace std;
struct car
{
string make;
int manfYear;
};
int num=0;
cout << "How many cars do you wish to catalogue? ";
cin >> num;
car * Cars = new car [num];
for (int i=1;i<=num;i++)
{
cout << "Car #" << i << ":" << endl << "Please enter the make: ";
std::cin.ignore();
getline(cin, Cars[i-1].make);
cout << "Please enter the year made: ";
cin >> Cars[i-1].manfYear;
}
}
There were also a couple of other minor niggles with your code.
1) You had been using Cars->manfYear - this will only ever point you to the first element of your array. I'm assuming you don't want that; using the subscripting syntax as per Cars[i-1].manfYear will access an individual car object in your array. (Remember that array indexes start from zero! - it would actually make more idiomatic sense for your for loop variable to start at zero as well really)
2) Be wary of the way std::getline and the >> symbol work together. the >> (stream extraction operator) often leaves any newline characters, which means you might see "odd" behaviour with your calls to getline. If you're mixing the two together, then using something like std::cin.ignore() will help you discard the newline character.
First of all, arrays in C++ are indexed from 0..n-1, so your loop needs to run from
for (int i = 0; i < num; i++) { ... }
Secondly, you've declared make as a 200-element array of pointer to char; this is most likely not what you want. If make is supposed to store a character string, declare it as a plain array of char:
struct car{
char make[200];
int manfYear;
};
Finally, rewrite your getline call as
cin.getline(Cars[i].make, sizeof Cars[i].make); // fixed per comment below
Even though Cars is declared as a pointer, you can use the subscript operator on it as though it were an array; by doing so, you implicitly dereference Cars, since a[i] is interpreted as *(a + i). This also means that you will use the . component selection operator as opposed to the -> operator, since the type of Cars[i] is car, not car *.
First of all char *make[200] is not a string of max 200 characters but 200 pointers to char.
Second thing: you are dereferencing the pointer in cin.getline with *: what happens is that you obtain the value contained in first cell of the 200 char* pointers. But you didn't initialize the single pointers, just the higher level one, so you get a segfault.
Just change char* make[200] to char make[200] and *Cars->make to Cars[i].make.

Segmentation fault when using stream extraction into a char pointer

I have a question. I have the following struct:
typedef struct{
int vin;
char* make;
char* model;
int year;
double fee;
}car;
Then I have the following method that asks the user for the make of a car and returns it as a char pointer:
char* askMake(){
char* tempMake = NULL;
cout << "Enter Make:" << endl;
cin >> tempMake;
return tempMake;
}
Then I have a temp car struct:
car tempCar;
And I am trying to assign a value to it this way:
tempCar.make = askMake();
It compiles fine, but I get a segmentation fault at runtime.
You haven't allocated any memory for tempMake to point at. When you read in the data, it's reading it into whatever random location tempMake happens to point at.
Get rid of the pointers and use std::string instead to make life a lot simpler.
You have to allocate memory for tempMake.
Try this:
char* askMake(){
char* tempMake = new char[1024]; //Arbitrary size
cout << "Enter Make:" << endl;
cin >> tempMake;
return tempMake;
}
Don't forget to free with delete[] the memory that you allocated.
If you don't want memory leaks, you can avoid this using smart pointers like boost::shared_ptr or boost::scoped_ptr or similar. You can see more about this here.
You really want to use std::string here instead of char*. The problem is that you are trying to read user input into memory (tempMake) that has not yet been allocated.
std::string askMake(){
std::string tempMake;
cout << "Enter Make:" << endl;
cin >> tempMake;
return tempMake;
}
You will also probably want to use std::string instead of char* in your 'car' struct as well.
You're getting a segfault because you're writing to a null pointer. You should create a new memory space for cin to write to, then copy it when it returns. std::string can do this for you:
std::string askMake() {
std::string temp;
cout << "Enter Make:" << endl;
cin >> temp;
return temp;
}
Others have told you what needs to be done to fix the immediate problem: either allocate space for tempMake using new or malloc, or else use a std:string.
You probably don't want to return a pointer to a struct's member from a function. While you can make correct code while doing so, and there are also very good reasons to do so, this might not be one of those instances. The problem has to do with ownership. If you expose the variable by pointer, then the end user is free to pass that guy around into other functions that may eventually free it before you want them to, or change it in some other way. Additionally, what happens when you decide to free that memory yourself? What if the guy on your team who doesn't know your code was using that pointer value after you deleted it? What if nobody frees it and you use this struct over and over? This is a memory leak.
The best model is to hide this functionality is to no allow direct access to your class members, and don't return a pointer from a function unless absolutely necessary. In C++, I think the most elegant solution would be to return a std::string. In straight C, instead pass a char** (let's call it x) into the function, and do this:
int askMake(char** x)
{
char tempMake[100];//or some value you know to be large enough
cout << "Enter Make:" << endl;
cin >> tempMake;//i would use cin.get() so you know the length of the string.
//so let's pretend we have that length in a variable called stringLen.
*x = new char[stringLen];
for(int i = 0; x && i < stringLen; i++)
{
(*x)[i] = tempMake[i];
}
if(x)
return 0;
else
return 1;
}
As others have said, you're giving yourself extra work by using char* instead of std::string. If you switch over to std::string it would look like this:
#include <string>
struct car
{
int vin;
std::string make;
std::string model;
int year;
double fee;
};
std::string askMake()
{
std::string make;
cout << "Enter Make:" << endl;
cin >> make;
return make;
}
int main()
{
car tempCar;
tempCar.make = askMake();
}