C++ code doesn't compile because of an error - c++

I'm currently solving problems for my high school final exam at programming in C++. I tried solving a problem in CodeBlocks, but it gives me this error at line 13:
error: invalid conversion from 'const char*' to 'int' [-fpermissive]
I don't see what is wrong.
The problem is about removing the last consonant from a string. The string is "mare frig saci" and it should produce "mare frig sai", removing the last 'c'.
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[256];
int i;
cin.get(s,256);
for(i=strlen(s)-1;i=0;i--)
{
if(strchr(s,"aeiou")!=0)
strcpy(s+i+1,s+i-1);
}
cout<<s;
return 0;
}

There are a few problems:
i=0 is not a condition, it's an assignment. i>=0 is probably what you're looking for here
strchr take in a string and char (1), and return a pointer (2), not an int to be compared. Both (1) and (2) condition isn't sastified. In any case, strchr is not ideal to use here.
I recommended using std::string (as it's more easy to use and standard in C++) and std::string::find_last_of, which find the last character in string inside a set of characters, exactly what you wanted here:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s; getline(std::cin, s);
string cons = "bcdfghjklmnpqrstvwxyz";
size_t pos = s.find_last_of(cons);
if (pos != string::npos) //if a consonant is found
{
s.erase(pos, 1);
}
cout << s;
}

std::strchr - The valid signatures are
const char* strchr( const char* str, int ch );
char* strchr( char* str, int ch );
So, you are supplying it with the wrong things.
std::strcpy - "The behavior is undefined if the strings overlap" - so you can't use std::strcpy to move the end of the string to the new place. Instead use std::memmove.
Since the string you mention contains a space at the end, you must add space to the list of vowels.
You assign 0 to i instead of checking it's value.
Example:
#include <cstring>
#include <iostream>
int main() {
char s[256] = " mare frig saci ";
for (size_t len = strlen(s), i = len; i-- > 0;) { // corrected loop
if (std::strchr("aeiou ", s[i]) == nullptr) { // corrected check
std::memmove(s + i, s + i + 1, len - i); // corrected move
break; // and break out
}
}
std::cout << s << '\n';
}

Related

i am trying to use getline to read a csv file line by line and separate the data in the file and turn a string into int

I am a beginner and I just need a bit of help on why I getline is showing an error:
this is what I have so far
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
const double TAX_RATE = 0.0825;
const int MAX_ITEMS = 1000;
const int MAX_TRANSACTIONS = 100;
int main(int argc, char const *argv[]){
string fname = "";
int itemCnt = 0, start = 0, end = 0;
int ids[MAX_ITEMS], qtys[MAX_ITEMS];
double costs[MAX_ITEMS], subtotals[MAX_TRANSACTIONS],
taxes[MAX_TRANSACTIONS], totals[MAX_TRANSACTIONS];
string names[MAX_ITEMS], paymentTypes[MAX_ITEMS], payments[MAX_ITEMS];
ifstream iFile;
if ( argc != 2 ) {
cout<<"usage: "<< argv[0]<< " <file name>" <<endl;
return 0;
} else {
iFile.open(argv[1]);
}
if (!iFile) {
cout<<"Error: Invalid file name"<<endl;
cin.clear();
}
while (!iFile.eof())
{
getline(iFile,str); //this isn't working
int commaLoc = str.find(',');
ids[itemCnt]= str.substr(0,commaLoc);
str = str.substr(commaLoc +1, str.length());
//string to int I'm not sure how to do I know its something with stoi() but not sure how to format it
}
return 0;
}
I am able to get the file to open but I'm not sure why getline isn't working it keeps saying something like
no instance of overload function
My csv file looks like:
1,Laptop,799.99,1,cash,1100
I need it to read the first number and because Its a string i don't know how to save it as an int
Multiple errors. First there is nothing called 'str' in your program. I will guess its just a string used as a temp buffer
do not do this (!File.eof) it doesnt do what you think.
while (iFile)
{
string str; <<<<<==== added
getline(iFile,str); //this isn't working <<<===is now
int commaLoc = str.find(',');
Next this line doesnt work because ids are ints and substring returns a string.
// ids[itemCnt]= str.substr(0,commaLoc);
ids[itemCnt]= stoi(str.substr(0,commaLoc)); <<<<==== fixed
str = str.substr(commaLoc +1, str.length());
}
I strongly recommend you use std::vector instead of c-style fixed size arrays. Takes 5 minutes to learn how to use them and they have huge benefits. If you must use fixed size arrays use std::array instead of c-style
You can read a string and try to convert it to a number in different ways. For example, since C++17, you can use from_chars. One of its overloads:
Receives a pair of begin and end char pointers, and an int variable,
tries to parse an int number, and
and returns the parsed number, together with a pointer to the first character that wasn't part of the match.
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) { /* do something with i */} else { /* error */ }
[Demo]
Full code (using a istrinstream instead of a ifstream):
#include <charconv> // from_chars
#include <iomanip>
#include <iostream>
#include <sstream> // istringstream
#include <system_error> // errc
constinit const int MAX_ITEMS = 10;
int main() {
std::istringstream iss{
"1,Laptop,799.99,1,cash,1100\n"
"2,PC,688.88,2,card,1101\n"
"blah,Keyboard,39.00,3,cash,1102"
};
size_t itemCnt{};
int ids[MAX_ITEMS]{};
std::string str{};
while (std::getline(iss, str)) {
// Parse counter
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) {
ids[itemCnt] = i;
// Remaining string
std::string remaining_string{ str.substr(ptr - str.data() + 1) };
std::cout << ids[itemCnt] << ", " << remaining_string << "\n";
}
else {
std::cout << "Error: invalid counter.\n";
}
++itemCnt;
}
}
// Outputs:
//
// 1, Laptop,799.99,1,cash,1100
// 2, PC,688.88,2,card,1101
// Error: invalid counter.

C++ segmentation fault while counting character occurrences in string

I've written a simple function to count occurrences of a character in a string. The compiler is fine. However, as I try to run it, it produced a segmentation fault.
#include <iostream>
using namespace std;
// To count the number of occurences of x in p
// p is a ะก-style null-terminated string
int count_x(char* p, char x)
{
if (p == nullptr)
{
return 0;
}
// start the counter
int count = 0;
while (p != nullptr)
{
if (*p == x)
{
++count;
}
}
return count;
}
int main(int argc, char const *argv[])
{
char myString[] = "Hello";
cout << count_x(myString, 'l');
return 0;
}
There's two mistakes in your code:
You only ever look at the first character in the string.
The last character of a null terminated string is a null character. You're testing the pointer itself.
You need to use std::string
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Hello";
std::cout << std::count(str.begin(), str.end(), 'l');
}

Segmentation Error

I am trying to implement my own shell in Linux. I take input from the user and parse it. But it gives segmentation error while I copy my tokens in a array. I am unable to solve this issue.
Here is the code I implemented
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
using namespace std;
int main ()
{
char * input;
string insert;
cout<<"My Shell $";
getline(cin,insert);
input= new char [insert.size()+1];
strcpy(input, insert.c_str());
char * token;
char * parsed[100];
int count;
token=strtok(input, " ");
while (token!=NULL)
{
strcpy(parsed[count],&(token[count]));
count++;
token=strtok(NULL, " ");
}
}
#include <string.h>
No.
If you want the C functions, use <cstring>, which puts them in the std:: namespace.
But you don't want the C functions, you want C++ <string>. Believe me, you do.
using namespace std;
I'll let that pass for the example's sake. Get out of that particular habit in any production code.
getline(cin,insert);
Good. You're ready to do C++.
input= new char [insert.size()+1];
strcpy(input, insert.c_str());
Bad. You just tied your hands to your back.
char * parsed[100];
An array of 100 pointers to char. Just the pointers, uninitialized, pointing nowhere.
int count;
Uninitialized.
token=strtok(input, " ");
C. shudder....
strcpy(parsed[count],&(token[count]));
Undefined behaviour. count is not initialized, and even if it does happen to be between 0 and 99, parsed[count] still does not point to valid memory, so copying something to it will do bad things.
Besides, your token is at token, not at token[count]...
count++;
Adding 1 to uninitialized is UB, and still uninitialized. ;-)
}
You forgot to delete [] input.
Let me suggest a different, more C++-ish approach, that will still give you your array of pointers to each token (if you insist on that):
getline( cin, input );
// turn spaces to null bytes
std::replace( input.begin(), input.end(), ' ', '\0' );
// need an additional one for the finds below to work
input.append( '\0' );
// vector takes away all of that manual memory management
std::vector< char * > parsed;
size_t i = 0;
// skip leading (ex-) spaces
while ( ( i = input.find_first_not_of( '\0', i ) ) != std::string::npos )
{
// push the pointer to the token on the vector
parsed.push_back( input.data() + i );
// skip to end of token
i = input.find( '\0', i );
}
At this point, parsed is a vector of char * to the tokens in input (at least, as long as input itself is still in scope). You can check its size with parsed.size(), and access it as "naked" array with parsed.data(), although I am sure you will find the vector more convenient.
If you don't want to keep input around, replace
std::vector< char * > parsed;
with
std::vector< std::string > parsed;
and
parsed.push_back( input.data() + i );
with
parsed.push_back( std::string( input.data() + i ) );
and you have a copy of the tokens in your vector.
That is still pretty rough handling, mind you, since even spaces inside of quotation marks will be detected as "end of token", but at least it's C++, none of that C string handling.
You didn't initialize the variable count, and its value is undefined(may be very large, so the program will fail reading from memory). You should use int count = 0;.
And the elements in the array parsed isn't initialized and does not point to allocated memory. The behavior of your call to strcpy is also undefined. Add parsed[count] = new char[strlen(token) + 1]; before your call to strcpy. Don't forget to use delete after everything is done.
At last, I think you didn't use strtok properly. Why did you use &(token[count])? Maybe you should replace it with token.
Variable int count is undefined, in means it can be random value, change it to int count = 0;
Just initialize your count variable to 0
Please try to use this code. I tried in VS2010 and it is working fine now.
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int main (void)
{
char* input = NULL;
string insert;
cout<<"My Shell $";
/* getline(cin, insert);*/
std::getline(cin, insert);
input= new char[insert.size() + 1];
strcpy(input, insert.c_str());
char* token = NULL;
char* parsed[100] = {0};
int count = 0;
token = strtok(input, " ");
while ( token != NULL)
{
parsed[count] = token;
count++;
token = strtok(NULL, " ");
}
for ( int index = 0; index<count; index++ )
{
cout << parsed[index] << std::endl;
}
system("pause");
return 0;
}
Please try the below code #
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;
int main (void)
{
char* input = NULL;
string insert;
cout<<"My Shell $";
getline(cin, insert);
input= new char[insert.size() + 1];
strcpy(input, insert.c_str());
char* token = NULL;
char* parsed[100];
for (int index = 0; index < 100; index++)
{
parsed[index] = NULL;
}
int count = 0;
token = strtok(input, " ");
while ( token != NULL)
{
strcpy(parsed[count], &(token[count]));
count++;
token = strtok(NULL, " ");
}
return 0;
}

How to find substring from string?

How do I find a substring from the string path "/user/desktop/abc/post/" using C/C++? I want to check if folder "abc" is present or not in that path.
Path is character pointer char *ptr = "/user/desktop/abc/post/";
Use std::string and find.
std::string str = "/user/desktop/abc/post/";
bool exists = str.find("/abc/") != std::string::npos;
In C, use the strstr() standard library function:
const char *str = "/user/desktop/abc/post/";
const int exists = strstr(str, "/abc/") != NULL;
Take care to not accidentally find a too-short substring (this is what the starting and ending slashes are for).
Example using std::string find method:
#include <iostream>
#include <string>
int main (){
std::string str ("There are two needles in this haystack with needles.");
std::string str2 ("needle");
size_t found = str.find(str2);
if(found!=std::string::npos){
std::cout << "first 'needle' found at: " << found << '\n';
}
return 0;
}
Result:
first 'needle' found at: 14.
Use strstr(const char *s , const char *t)
and include<string.h>
You can write your own function which behaves same as strstr and you can modify according to your requirement also
char * str_str(const char *s, const char *t)
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++)
{
for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++);
if (k > 0 && t[k] == '\0')
return (&s[i]);
}
return NULL;
}
As user1511510 has identified, there's an unusual case when abc is at the end of the file name. We need to look for either /abc/ or /abc followed by a string-terminator '\0'. A naive way to do this would be to check if either /abc/ or /abc\0 are substrings:
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "/user/desktop/abc";
const int exists = strstr(str, "/abc/") || strstr(str, "/abc\0");
printf("%d\n",exists);
return 0;
}
but exists will be 1 even if abc is not followed by a null-terminator. This is because the string literal "/abc\0" is equivalent to "/abc". A better approach is to test if /abc is a substring, and then see if the character after this substring (indexed using the pointer returned by strstr()) is either a / or a '\0':
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "/user/desktop/abc", *substr;
const int exists = (substr = strstr(str, "/abc")) && (substr[4] == '\0' || substr[4] == '/');
printf("%d\n",exists);
return 0;
}
This should work in all cases.
If you are utilizing arrays too much then you should include cstring.h because it has too many functions including finding substrings.

Reversing a string, weird output c++

Okay, so I'm trying to reverse a C style string in C++ , and I'm coming upon some weird output. Perhaps someone can shed some light?
Here is my code:
int main(){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-1;
int i =0;
while (&str+n >= &str){
str2[i] = *(str+n);
n--;
i++;
}
int str2size = sizeof(str)/sizeof(char);
int x;
for(x=0;x<str2size;x++){
cout << str2[x];
}
}
The basic idea here is just making a pointer point to the end of the string, and then reading it in backwards into a new array using pointer arithmetic.
In this particular case, I get an output of: " gnirts"
There is an annoying space at the beginning of any output which I'm assuming is the null character? But when I try to get rid of it by decrementing the strSize variable to exclude it, I end up with some other character on the opposite end of the string probably from another memory block.
Any ideas on how to avoid this? PS: (would you guys consider this a good idea of reversing a string?)
A valid string should be terminated by a null character. So you need to keep the null character in its original position (at the end of the string) and only reverse the non-null characters. So you would have something like this:
str2[strSize - 1] = str[strSize - 1]; // Copy the null at the end of the string
int n = strSize - 2; // Start from the penultimate character
There is an algorithm in the Standard Library to reverse a sequence. Why reinvent the wheel?
#include <algorithm>
#include <cstring>
#include <iostream>
int main()
{
char str[] = "string";
std::reverse(str, str + strlen(str)); // use the Standard Library
std::cout << str << '\n';
}
#ildjarn and #Blastfurnace have already given good ideas, but I think I'd take it a step further and use the iterators to construct the reversed string:
std::string input("string");
std::string reversed(input.rbegin(), input.rend());
std::cout << reversed;
I would let the C++ standard library do more of the work...
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
typedef std::reverse_iterator<char const*> riter_t;
char const str[] = "string";
std::size_t const strSize = sizeof(str);
char str2[strSize] = { };
std::copy(riter_t(str + strSize - 1), riter_t(str), str2);
std::cout << str2 << '\n';
}
while (&str+n >= &str){
This is nonsense, you want simply
while (n >= 0) {
and
str2[i] = *(str+n);
should be the much more readable
str2[i] = str[n];
Your while loop condition (&str+n >= &str) is equivalent to (n >= 0).
Your *(str+n) is equivalent to str[n] and I prefer the latter.
As HappyPixel said, your should start n at strSize-2, so the first character copied will be the last actual character of str, not the null termination character of str.
Then after you have copied all the regular characters in the loop, you need to add a null termination character at the end of the str2 using str2[strSize-1] = 0;.
Here is fixed, working code that outputs "gnirts":
#include <iostream>
using namespace std;
int main(int argc, char **argv){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-2; // Start at last non-null character
int i = 0;
while (n >= 0){
str2[i] = str[n];
n--;
i++;
}
str2[strSize-1] = 0; // Add the null terminator.
int str2size = sizeof(str)/sizeof(char);
int x;
cout << str2;
}