ERROR char and const char - c++

I am quite new to programming and the code that I made has confused me. can you please explain the following errors.
int getBill(char seat)// a return function.
{
int b=0;
char FS, fs, LBS, lbs, UBS, ubs, GPS, gps;
char seat;
if(seat=="FS"||seat=="fs")
b=15000;
if(seat=="LBS"||seat=="lbs")
b=10000;
if(seat=="UBS"||seat=="ubs")
b=5000;
if(seat=="GPS"||seat=="gps")
b=1500;
return b;
}
ERROR: Operand types are incompatible( char and const char)

Change your function to take a std::string rather than a single char. And remove the extra char declarations.
int getBill(const std::string &seat)// a return function.
{
int b=0;
if(seat=="FS"||seat=="fs")
....
Note that it's usually much more efficient to pass in structures by const reference as shown above.

Your code looks like C code. In C "strings" are arrays of bytes. Most functions figure out the end of said array by whats known as a "zero terminator" (a byte with the value of zero). Individual elements of the string (or "array") are referred to as "char" for character.
Logic operations can only be performed on "items" which fit into CPU registers i.e. comparing a single byte to another byte, an integer to another integer. In order to compare strings, you need to perform a loop, comparing each character (byte) of the strings (arrays). Luckily C comes with a standard library, which among lots of other useful stuff, contains functions for manipulating strings. Specifically the function strcmp will compare two strings, and return the difference of first non-matching character or zero if a zero-terminator is encountered.
To implement you getBill routine using strcmp, you would do something like:
#include <string.h> /* contains definition of strcmp() */
int getBill(char *seat)
{
int b=0;
char seat;
if(0 == strcmp(seat, "FS") || 0 == strcmp(seat,"fs"))
b=15000;
if(0 == strcmp(seat, "LBS") || 0 == strcmp(seat, "lbs"))
b=10000;
if(0 == strcmp(seat, "UBS") || 0 == strcmp(seat, "ubs"))
b=5000;
if(0 == strcmp(seat, "GPS") || 0 == strcmp(seat, "gps"))
b=1500;
return b;
}
/* example use: */
getBill("FS);
A little more "advanced" solution, would be to use a "case-insensitive" compare function, and put definied values in a "table". Something like:
#include <string.h> /* contains definition of stricmp() */
static const char* bill_types_str[] =
{
"fs", "lbs", "ubs", "gps"
};
static const int bill_type_ids[] =
{
15000, 10000, 5000, 1500
};
int getBill(char *seat)
{
for(i=0; i < sizeof(bill_types_str)/sizeof(bill_types_str[0]; i++)
if (0 == stricmp(seat, bill_types_str[i]))
return bill_types_id[i];
return 0;
}
Doing it like this, makes it really easy to add new "bill types", and also allows for later functionality to list the supported "bill types".

You are trying to compare sting (or char array) with char.
Do you mean?
char seat[SOME_INT_VALUE];
instead of just
char seat

Related

return a char function with random options and local variables

I have created a unit test harness to test my program. I wanted it to be able to randomly test each run but I'm not sure how to go about doing this. Here is what I was think but I get stuck on what to do next, any guidance would be much appreciated.
int main (void)
{
int testNumber = 1; //for testing
char carName[] = "";
double carCost = 0;
carName = carChosen (testNumber);
carCost = assessCost (carName); //assessCost takes in the car name and checks what cost of the car will be (error checking so only certain cars can be chosen)
return 0;
}
"testNumber" would normally be seeded with time to create different number's from 1 - 15, but in this situation it's going to be "1" for testing.
This is next bit that I'm having trouble with. Within this function there would be 15 diffrent car options and it will return one depending on the randomly created number.
char carChosen (int randNum)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
return carOne; //local variables, not going to work...
}
else if (randNum == 2)
{
return carTwo; // Again, these return's are here to better represent what I'm trying to create but failing to do so..
}
}
I understand you cannot return local variables, what can I do instead?
This
void carChosen (int randNum, char * out)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
strcpy(out, carOne);
}
else if (randNum == 2)
{
strcpy(out, carTwo);
} //.. handle other cases
}
Call like
char carName[MAX_LEN];
carChosen (testNumber, carName);
Also maybe you are better of using switch instead of nested if..else if you have many conditions to test.
I thought it was C looking at the code, if you use C++, you can just return std::string objects from your function without any issues.
As others have pointed out, your code looks like C code. If you want to use C++, then read up on std::string and use that.
If you want to continue with your approach (which is very much a C-like approach), then you'll need to better understand how C strings work. Namely, how they are stored in memory and how a char is different from a char * is different from a char array[].
Putting most of that aside for now, my first guess based upon your example code is that you won't actually be modifying the contents of the string. You just want the string for its contents, but you won't be changing them. If this is accurate than you can just use regular char * variable to hold a pointer to a char string. You only need one copy of the string hanging around, so you can pass around a pointer to that one copy and everyone can read from that pointer. A quick way to do this is to just use the string literal directly.
const char* carChosen (int randNum)
{
if (randNum == 1)
{
return "Honda";
}
else if (randNum == 2)
{
return "Ford";
}
else
{
return "Audi";
}
}
Note that we are returning a const char *. The const is just indicating that we will not be modifying the string that is pointed to. We definitely do not want to do that because it points to a string literal (which you are not allowed to modify). Once you have the const char * returned by carChosen, you can pass that along to other functions, e.g. assessCost.

Boolean function does not work properly

I have trouble to come up with a Boolean function as expected by the assignment. I just need some explanations as I want to write my own code. I am supposed to write a MIPS code that actually counts the number of Uppercase, Lowercase, Vowels, Consonants and Digits in a string. I am writing the code in C++, then I will translate into MIPS assembly. I pasted the requirement below followed by the way the function bool consonant(char c) should look like (idea given by my professor). The problem is that it seems I am missing some information to make that function work. Can anyone provide me more information regarding that function? I don't need a code, just the missing details. Your help will be very appreciated.
//requirement of assignment bellow
To determine if an ASCII character c is a vowel or a consonant, write two functions bool vowel(char c) and
bool consonant(char c). Use the stack to pass the character argument to these functions. Avoid long conditional
expressions when testing a character for being a vowel and a consonant. Instead, use two global arrays
(tables) containing Boolean flags to implement vowel() and consonant(). For example, an array named
is_vowel would have true for characters ’a’ and ’A’ but false for ’b’ and ’B’.
// function that returns 0 if c is a consonant, or 1 if c is not a consonant
bool consonant(char c)
{
const bool is_conson[30]={0,0,...1,1,1,0,0...};
return is_conson[c];
}
//Here is The Code (C++) that I wrote for testing purpose only using Dev-C++
#include <iostream>
#include <math.h>
#include <cstdlib>
using namespace std;
bool consonant(char c)
{
const bool is_conso[30]= {1,1,1,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1};
return is_conso[c];
}
int main()
{
int i;
bool result;
char c;
char sentence[]="aaaabbbbb";
cout<<"the array: ";
cout<<sentence<<endl;
for (i=0; i<9; i++)
{
c=sentence[i];
result=consonant(c);
if (result==0)
cout<<c<<" is a Consonant"<<endl;
}
return 0;
}
If you want to call bool consonant(char c) like consonant('a'), then you need to translate c into an index first (because 'a' != 0) or use another approach.
In portable C++, you could do it with a big switch:
switch(c) {
case 'b': case'B': case 'c': case 'C': .... return true;
default: return false;
}
In non-portable C++, you could offset c:
c = lower_case(c); // <-- left as exercise
const auto array_size = std::end(is_conson) - std::begin(is_conson);
if (c>=0 && c<array_size)
return is_conson[c - 'a']
throw std::logic_error(...);
This is non-portable because the C++ standard does not require the characters [a..z] to be contiguous. I don't know if your compiler at hands does support this.
A third, non-portable variant requires separate some special initialization, but allows direct indexing:
std::array<bool,std::numeric_limits<char>::max()> meh() {
std::array<bool,std::numeric_limits<char>::max()> ret;
ret['a'] = true;
ret['A'] = true;
...
return ret;
}
....
static const auto is_conson = meh();
if (c >= begin(is_conson) && c<= end(is_conson))
return is_conson[c];
throw std::logic_error(....);
Non-portable, because it assumes that all consonants are positive. It is, however, more portable than the previous variant. You could make it portable by also introducing std::numeric_limits<char>::min().
As it stands your function won't work because ASCII A is 65, you'll need to increase your array to cover all ASCII characters or subtract 'A' (which gives the ASCII value of A) to scale the number to your array. ASCII a is 97, so lowercase letters would have to be scaled by subtracting 'a'
Letters are represented by values 65 through 90 (uppercase) and 97 through 122 (lowercase) in ASCII. You're using the array as if they were starting at index 0. Do something like this:
if (c >= 'A' && c <= 'Z')
return is_conson[c-'A'];
if (c >= 'a' && c <= 'z')
return is_conson[c-'a'];
return false;
Also, you should declare the is_conson array as static, so that it's only constructed once and not each time the function is called.

Convert Int to Char Array

I need to make a class called MyInt which handles any size positive numbers by creating an int array. I am making a constructor to be used in converting an int (any size supported by ints) into a MyInt. I need to convert the int into a char array and then read digit by digit into the int array. So my question is, without using any libraries except <iostream> <iomanip> and <cstring> how can I convert an int with multiple digits into a character array?
You don't need to make a char array as an intermediary step. The digits (I assume in base 10) can be obtained one by one using modulo 10 operations. Something like:
convert(int *ar, const int i)
{
int p, tmp;
tmp = i
while (tmp != 0)
{
ar[p] = tmp % 10;
tmp = (tmp - ar[p])/10;
p++;
}
}
Not sure if this is what you want, but:
int myInt = 30;
char *chars = reinterpret_cast<char*>(&myInt);
And you can get the 4 separate char's:
chars[0]; // is the first char
chars[1]; // is the second char
chars[2]; // is the third char, and
chars[3]; // is the fourth/last char
...but I'm not entirely sure if that's what you are looking for.
One possible way of doing that conversion with such restraints is as follows:
function convert:
//find out length of integer (integer division works well)
//make a char array of a big enough size (including the \0 if you need to print it)
//use division and modulus to fill in the array one character at a time
//if you want readable characters, don't forget to adjust for them
//don't forget to set the null character if you need it
I hope I didn't misunderstand your question, but that worked for me, giving me a printable array that read the same as the integer itself.

using qsort causing a segmentation fault

Well, as part of learning C++, my project has a restriction on it. I'm not allowed to use any libraries except the basic ones such as <cstring> and a few other necessities.
The project should take in input from a file that is an "n" number of columns of strings and be able to sort the output according to lexicographical ordering of any selected column. So for example, given the input
Cartwright Wendy 93
Williamson Mark 81
Thompson Mark 100
Anderson John 76
Turner Dennis 56
It should sort them by column. And my search around StackOverflow returned a result from someone else who had to do the exact same project a few years ago too Hahaha Qsort based on a column in a c-string?
But in my case I just use a global variable for the column and get on with life. My problem came in when I am implementing the compare function for qsort
In my main method I call
qsort (data, i, sizeof(char*), compare);
where data is a char * data[] and i is the number of lines to compare. (5 in this case)
Below is my code for the compare method
int compare (const void * a, const void * b){
char* line1 = new char[1000]; char* line2 = new char[1000];
strcpy(line1, *((const char**) a));
strcpy(line2, *((const char**) b));
char* left = &(strtok(line1, " \t"))[column-1];
char* right = &(strtok(line2, " \t"))[column-1];
return strcmp(left, right);
}
the 1000s are because I just generalized (and did bad coding on purpose) to overgeneralize that no lines will be longer than 1000 characters.
What confuses me is that when I use the debugger in Eclipse, I can see that it it compares it successfully the first time, then on the second round, it has a segmentation fault when it tries to compare them.
I also tried to change the code for assigning left and right to what is below but that didn't help either
char* left = new char[100];
strcpy(left, &(strtok(line1, " \t"))[column-1]);
char* right = new char[100];
strcpy(right, &(strtok(line2, " \t"))[column-1]);
Please help me understand what is causing this segmentation fault. The first time it compares the two, left = "Williamson" and right = "Thompson". The second time it compares (and crashes trying) left = "Cartwright" and right = "Thompson"
char* line1 = new char[1000]; char* line2 = new char[1000];
This is not good at all. You're never freeing this, so you leak 2000 bytes every time your comparison function is called. Eventually this will lead to low-memory conditions and new will throw. (Or on Linux your process might get killed by the OOM-killer). It's also not very efficient when you could just have said char line1[1000], which is super-quick because it simply subtracts from the stack pointer rather than potentially traversing a free list or asking the kernel for more memory.
But really you could be doing the compare without modifying or copying the strings. For example:
static int
is_end_of_token(char ch)
{
// If the string has the terminating NUL character we consider it the end.
// If it has the ' ' or '\t' character we also consider it the end. This
// accomplishes the same thing as your strtok call, but WITHOUT modifying
// the source buffer.
return (!ch || ch == ' ' || ch == '\t');
}
int
compare(const void *a, const void *b)
{
const char *strA = *(const char**)a;
const char *strB = *(const char**)b;
// Loop while there is data left to compare...
while (!is_end_of_token(*strA) && !is_end_of_token(*strB))
{
if (*strA < *strB)
return -1; // String on left is smaller
else if (*strA > *strB)
return 1; // String on right is smaller
++strA;
++strB;
}
if (is_end_of_token(*strA) && is_end_of_token(*strB))
return 0; // both strings are finished, so they are equal.
else if (is_end_of_token(*strA))
return -1; // left string has ended, but right string still has chars
else
return 1; // right string has ended, but left string still has chars
}
But lastly... You're using std::string you say? Well, if that's the case, then assuming the memory passed to qsort is compatible with "const char **" is a little weird, and I would expect it to crash. In that sense maybe what you should do something like:
int compare(const void *a, const void *b)
{
const char *strA = ((const std::string*)a)->c_str();
const char *strB = ((const std::string*)b)->c_str();
// ...
}
But really, if you are using C++ and not C, you should use std::sort.

Accepting a grammar in C++

This is a lab assignment I am stuck on.
I need to accept this grammar (ab)*b, which basically means any number of "ab" and ending with b.
I have written this code but somehow, it checks only the first 2 letters.
#include <iostream.h>
#include <conio.h>
#include <string.h>
enum track {true, false};
void main()
{
clrscr();
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
cin>>str;
int len=strlen(str);
cout<<"length of the string is "<<len;
getch();
int i;
for(i=0;i<len; i++)
{
++str;
cout<<"loop"<<i;
if(*str=='a' && i%2==0)
{
cout<<"\nchecking a...";
track_pos=true;
cout<<"\na.check";
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
if(ch=='y' || ch=='Y')
main();
}
I'm going to regret this, but each time I look at this question I see something else wrong with your code. Here is the line by line. I've probably missed a lot.
The correct name for this header is "iostream", not "iostream.h" - the ".h" version is deprecated. Similarly, use "string", not "string.h" in modern C++, and use the modern STL string classes.
#include <iostream.h>
#include <conio.h>
#include <string.h>
As pointed out, don't do this. You have redefined the standard bool type to have the opposite value from the standard types. I don't even know that this is legal.
enum track {true, false};
The return value of the main function is int, not void.
void main()
{
clrscr();
Do you know what a buffer overflow is? You have defined str as a pointer here, with no allocated memory, and you write to that undefined bit of memory a bit later on. This is undefined behaviour, and you are pretty much guaranteed to crash. I recommend, you should defined str as a std::string - this will nicely avoid the buffer overflow, and it has many useful methods that you can use in your program.
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
This is the buffer overflow right here. You are writing to who knows what area of memory.
cin>>str;
If str was a std::string - you would do size_t len=str.length();
int len=strlen(str);
cout<<"length of the string is "<<len;
It's probably not a good idea to mix console IO functions like this with iostreams functions - there are some buffering issues that can lead to difficulties.
getch();
Declare i in the body of the loop, since you aren't using it again. Like so:
for (int i=0; i<len; i++) etc...
int i;
for(i=0;i<len; i++)
{
Instead of using poiter arithmetic, since you are keeping track of the index of the current character in i, just use that and treat str as an array. This way, you don't have to keep str in synch with i all of the way through. This is the cause the bug you are reporting, by the way.
++str;
cout<<"loop"<<i;
You should change this to:
if (str[i]=='a' && i%2==0)
(That works even if str is a std::string by the way, unlike the pointer arithmetic version).
if(*str=='a' && i%2==0)
{
You really should drop out at some point, if you figure out that the string doesn't match, then there is no point going on to the end of the string.
cout<<"\nchecking a...";
I don't favour status flags like this - your code is partly hard to understand because of the proliferation of these flags, you cannot keep track of the proper behaviour. The name track_pos is not mnemonic, that makes it hard to work out what it is meant to signify without detailed study of the code.
I would recommend that you would refactor your code inside the body of the for loop to call a function, the purpose of which is simply to match a single group of "ab" - this function could return true if it did, and false if it did not.
track_pos=true;
cout<<"\na.check";
Note that since we are dealing with the buffer overflow mentioned before, you are iterating undefined memory. Also note that you did not increment i here.
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
When we get to here, according to your for loop, we have iterated the whole string, so we must be looking past the end of the string (even ignoring the buffer overflow) so there is no possible way this test can succeed. In short, your for loop must be going too far.
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
Should I mention the spelling mistake?
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
If you refactor your code into appropriate sub-routines, you will find the structure of the program takes care of itself. Note that calling main recursively is not strictly illegal, but it is kind of weird and has an obvious vulnerability that will lead to an eventual stack overflow, if the program never exits.
if(ch=='y' || ch=='Y')
main();
}
Implement a simple state machine. It has these states:
0 = start
1 = 'received a of (ab)'
2 = 'received b of (ab)'
3 = 'received final b'
-1 = error, invalid grammar
Then you just need a function like this:
int nextState(int currentState, char inputChar) {
if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
return -1;
}
Iterate this "state machine" over your input chars, starting with state 0, and if you end up in state 3, your input is valid.
int isValid(char* inputString) {
int state = 0;
for(int i=0; i<str_len(inputString); i++) {
state = nextState(state, inputString[i]);
}
return (state == 3);
}
Things wrong with your code:
#include <iostream.h>
should be:
#include <iostream>
The following is a non-standard (and very old) header:
#include <conio.h>
The following is illegal - true and false are reserved words.
enum track {true, false};
In C and C++, main must return an int:
void main()
Non standard function:
clrscr();
No memory allocated to this pointer:
char*str;
which is then used here - result undefined behaviour:
cin>>str;
Illegal call to main:
main();
I suspect you are using a very old and obsolete C++ compiler. You should replace it with something like MinGW.
Don't do this!
enum track {true, false};
Here your true is equal to 0 and false is equal to one! When you later assign track_pos, you may get the wrong value! (Because when converting bool to int, true converts to 1 and false converts to 0.)
That's only a guess though. Maybe it's something else that matters.