Strings C++

Pages: 12
There are two strings with dynamic size. It's needed to write a function which returns true if these strings have at least one same character and false if they don't. Maximum size and strings should be inputted from file. <cstring> can't be used.

I wrote something but is's such a mess cause bool function returns wrong value and there's an error "33 22 [Error] no matching function for call to 'getline(std::ifstream&, std::vector<std::basic_string<char> >&)''. I'd be so greatful if you'll help me fix it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <vector>
#include <fstream>
#include <string>

const char* ERROR_FILE = "Error: file is not opened";

bool findSame(std::vector<std::string> str1, std::vector<std::string> str2) 
{
	int i, j;
	for(i = 0; i <= str1.size(); i++)
 {
	for ( j= 0; str1[i] != str2[j]; j++); 
    return false;
 }
  return true;
}

int main()
{
   int line_size;
   std::vector<std::string> str1, str2;
  
   std::ifstream file ("input1.txt");
   if(!file.is_open())
  {
  	throw ERROR_FILE;
  }
  while(!file.eof())
  {
  	file >> line_size;
  	
  	getline(file, str1);
  	str1_push.back(str1);
  	
  	getline(file, str2);
  	str1.push_back(str1);
  }
    file.close();
    bool findSame( str1,  str2);
    
    str1.clear();
    str2.clear();
    
	return 0;
}
 
thats ok. messy wrong code where you tried is much more awesome than 'trust me, I tried, now write it for me'.

hang on!

line 33 needs to getline into a string, not a vector of string.
eg
string line;
getline(file, line);
str1.push_back(line);

if you had preallocated the vector, you can also fill it:
getline(file, str1[index]); //but [index] has to exist.
later, you want to try to preallocate vectors, but for now, don't stress over it if its a new idea.
Last edited on
Since you are reading from a file could you please provide a sample of the contents for testing?

Line 40, please remove the bool type from the function call. You are not defining the function. you are using it.
here's content:

15
psychohazardous
Waste

and i remarked something but it can't read from file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
   std::string line1, line2;
   int line_size;
   std::vector<std::string> str1, str2;
  
   std::ifstream file ("input1.txt");
   if(!file.is_open())
  {
  	throw ERROR_FILE;
  }
  while(!file.eof())
  {
  	file >> line_size;
  	
  	getline(file, line1);
  	str1.push_back(line1);
  	
  	getline(file, line2);
  	str2.push_back(line2);
  }
    file.close();
    bool findSame( std::vector<std::string> str1, std::vector<std::string> str2 );
    
    str1.clear();
    str2.clear();
    
	return 0;
}
Last edited on
don't mix >> << stream operations and getline. If you do that you need an ignore() but here, you don't use the size, maybe you can read that as a line/string and throw it away? It seems to serve no purpose.
@tapni

Line 12: Do not loop on (! stream.eof()) or (stream.good()). This does not work the way you expect. The eof bit is set true only after you make a read attempt on the file. This means after you read the last record of the file, eof is still false. Your attempt to read past the last record sets eof, but you're not checking it there. You proceed as if you had read a good record. This will result in reading an extra (bad) record. The correct way to deal with this is to put the >> (or getline) operation as the condition in the while statement.
1
2
3
  while (stream >> var) // or while (getline(stream,var))
  {  //  Good operation
  }
It's needed to write a function which returns true if these strings have at least one same character and false if they don't


To check 2 strings for at least one same:

1
2
3
4
5
6
#include <string_view>

bool oneSame(std::string_view s1, std::string_view s2)
{
	return s1.find_first_of(s2) != std::string_view::npos;
}

Perhaps (not tried) for multiple strings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <vector>

bool findSame(const std::vector<std::string>& str1, const std::vector<std::string>& str2) {
	for (const auto& s : str2)
		if (std::find(str1.begin(), str1.end(), s) != str1.end())
			return true;

	return false;
}

int main() {
	size_t line_size {};
	std::vector<std::string> str1, str2;
	std::ifstream file("input1.txt");

	if (!file)
		return (std::cout << "Cannot open file\n"), 1;

	for (std::string line1, line2; file >> line_size; ) {
		getline(file >> std::ws, line1);
		str1.push_back(line1);

		getline(file, line2);
		str2.push_back(line2);
	}

	std::cout << std::boolalpha << findSame(str1, str2) << '\n';
}


but what, exactly, are you trying to achieve? You mention strings that have at least one same character - but have a function to check for same string with vector??
Last edited on
but being stated that you can't use <cstring> and having line size specified in the file sort of suggests you are expected to use c-style strings (not std::string or std::string_view) - and that you are expected to 'roll your own' strcspn() ????
Why, oh, why, tapni, are you creating two vectors that contain C++ strings? You use the two vectors as if they were C string arrays.

Create ONE vector and push both read string into the single vector. Then you can access the two strings using the vector's operator[].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <vector>
#include <string>

void Display(const std::vector<std::string>&);

int main()
{
   std::vector<std::string> str;

   str.push_back("Hello");     // str[0]
   str.push_back(" World!\n"); // str[1]

   Display(str);
}

void Display(const std::vector<std::string>& str)
{
   std::cout << str[0] << str[1];
}

Hello World!
This only works when the words being read from the file don't contain spaces, using your input file, discarding "the size" entry:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <vector>
#include <string>
#include <fstream>

void Display(const std::vector<std::string>&);

int main()
{
   std::vector<std::string> str;

   std::ifstream file("input1.txt");

   if (!file.is_open())
   {
      std::cerr << "ERROR!  File not opened\n";

      throw -1;
   }
   else
   {
      std::string input;

      file >> input;  // reads the 15, discarded

      // reads all the words you want stored
      // when the file hits EOF the loop is terminated
      while (file >> input)
      {
         str.push_back(input);
      }

      Display(str);
   }
}

void Display(const std::vector<std::string>& str)
{
   for (const auto& itr : str)
   {
      std::cout << itr << '\n';
   }
}

psychohazardous
Waste

Since you are using C++ strings there are algorithms available to compare the two strings. Either the entire strings or parts.
would putting the letters from each into <set>s and then doing an intersection be as fast as the counting sort approach...? It would be minimal code. and it would work in unicode.

.... I always forget how messed up <set> is.
but that idea, using more useful containers, is only:

1
2
3
4
5
6
7
8
9
10
11
int main()
{   
   string f{"psychohazardous"}, s{"waste"};
   vector<char> result(30,0);
   std::sort(f.begin(), f.end());
   std::sort(s.begin(), s.end());     
   set_intersection(f.begin(), f.end(), s.begin(), s.end(),result.begin());
   char *r = &result[0];
   while(*r) cout << *r << endl,++r;   
}

which means that if result[0] isnt zero, they share a letter if you want the bool response.
Given that you have to sort the strings, its probably not the fastest possible. But its simple enough -- the actual bool result is obtainable from only lines 5,6,7 given that your variables and my printer loop don't matter.
Last edited on
Both I and JLBorges already gave responses on OPs duplicate thread using sets. You will not get better performance than that. No need to perform any sorting.

1
2
3
4
5
6
7
8
9
#include <unordered_set>

bool has_common_codepoints( const std::string& a, const std::string& b )
{
  std::unordered_set <char> cs;
  for (auto c : a) cs.insert( c );
  for (auto c : b) if (cs.count( c )) return true;
  return false;
}
Last edited on
I saw. I was just trying to play with the intersection idea. I rarely use those and forgot that it was about useless -- you would think <set> would just have an intersect with another set that was efficient, but ... swing & a miss.
Last edited on
Ah, yes, a set intersection would be a nice function. Gonna play with that. ;-)
‘Twas easier than I thought it would be.

1
2
3
4
5
6
7
8
9
template <typename Set>
Set intersection( const Set& A, const Set& B )
{
  Set R;
  for (auto x : A)
    if (B.count( x ))
      R.insert( x );
  return R;
}
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_set>

using set = std::unordered_set <std::string> ;


std::istream& operator >> ( std::istream& ins, set& S )
{
  std::string s;
  getline( ins, s );
  std::istringstream ss( s );
  while (ss >> s) S.insert( s );
  return ins;
}


std::ostream& operator << ( std::ostream& outs, const set& S )
{
  const char * s[] = { "", " " };
  std::size_t n = 0;
  for (const auto& x : S) outs << s[!!n++] << x;
  return outs;
}


int main()
{
  set A;
  std::cout << "Enter first set: ";
  std::cin >> A;

  set B;
  std::cout << "Enter second set: ";
  std::cin >> B;

  std::cout << "Set intersection: " << intersection( A, B ) << "\n";
}
Last edited on
@Duthomhas

Sorry if have the wrong end of the stick, but isn't R in the first code snippet an xvalue? Would one need to return the type Set& instead? Or make it an out parameter?
> you would think <set> would just have an intersect with another set

The standard algorithm for set intersection for sorted ranges:
https://en.cppreference.com/w/cpp/algorithm/set_intersection
https://en.cppreference.com/w/cpp/algorithm/ranges/set_intersection
I don't know of any words that have a space in them but it doesn't matter anyway.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>

const int NO_LETTERS{26};

void check(const std::string str, int* alp, int sz)
{
    char temp;
    for(int i = 0; i < str.length(); i++)
    {
        temp = tolower(str[i]);
        if(alp[temp - 'a'] == 0)
            alp[temp - 'a']++;
    }
}

void compare(int* a1, int* a2, int sz)
{
    for(int i = 0; i < 26; i++)
    {
        if(a1[i] == 1 && a2[i] == 1)
            std::cout << (char)('a' + i) << ' ';
    }
}

int main()
{
    int alphabet_1st_word[NO_LETTERS]{0};
    int alphabet_2nd_word[NO_LETTERS]{0};
    
    std::string string1{"Wastez"};
    std::string string2{"psychohazardous"};
    
    check(string1, alphabet_1st_word, NO_LETTERS);
    check(string2, alphabet_2nd_word, NO_LETTERS);
    
    compare(alphabet_1st_word, alphabet_2nd_word, NO_LETTERS);
    return 0;
}



a s z Program ended with exit code: 0
Pages: 12