Strings C++

Pages: 12
Nov 8, 2021 at 6:26pm
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;
}
 
Nov 8, 2021 at 6:39pm
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 Nov 8, 2021 at 6:43pm
Nov 8, 2021 at 6:46pm
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.
Nov 8, 2021 at 7:09pm
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 Nov 8, 2021 at 7:10pm
Nov 8, 2021 at 8:40pm
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.
Nov 8, 2021 at 8:44pm
@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
  }
Nov 9, 2021 at 1:50am
Nov 9, 2021 at 11:13am
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;
}

Nov 9, 2021 at 11:30am
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 Nov 9, 2021 at 12:09pm
Nov 9, 2021 at 5:42pm
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() ????
Nov 9, 2021 at 7:21pm
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!
Nov 9, 2021 at 7:36pm
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.
Nov 9, 2021 at 9:37pm
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 Nov 9, 2021 at 10:11pm
Nov 9, 2021 at 10:27pm
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 Nov 9, 2021 at 10:29pm
Nov 9, 2021 at 10:55pm
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 Nov 9, 2021 at 10:59pm
Nov 9, 2021 at 11:42pm
Ah, yes, a set intersection would be a nice function. Gonna play with that. ;-)
Nov 9, 2021 at 11:58pm
‘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 Nov 9, 2021 at 11:59pm
Nov 10, 2021 at 12:50am
@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?
Nov 10, 2021 at 12:54am
> 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
Nov 10, 2021 at 1:19am
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