"no matching function calling for getline" error

Pages: 12
I got this Build message:

1>------ Build started: Project: chapter17ex7, Configuration: Debug Win32 ------
1>chapter17ex7.cpp
1>chapter17ex7.cpp(18,36): error : no matching function for call to 'getline'
1> for (char *str = new char[32737]; std::getline(std::cin, std::string(str), '\n') && *str != '!';)
1> ^~~~~~~~~~~~
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\include\string(144,33) : note: candidate function [with _Elem = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] not viable: expects an l-value for 2nd argument
1> basic_istream<_Elem, _Traits>& getline(
1> ^
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\include\string(71,33) : note: candidate function [with _Elem = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] not viable: no known conversion from 'istream' (aka 'basic_istream<char, char_traits<char> >') to 'basic_istream<char, std::char_traits<char> > &&' for 1st argument
1> basic_istream<_Elem, _Traits>& getline(
1> ^
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\include\string(124,33) : note: candidate function template not viable: requires 2 arguments, but 3 were provided
1> basic_istream<_Elem, _Traits>& getline(
1> ^
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\include\string(155,33) : note: candidate function template not viable: requires 2 arguments, but 3 were provided
1> basic_istream<_Elem, _Traits>& getline(
1> ^
1>1 error generated.
1>Done building project "chapter17ex7.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


when trying to build this code:
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
// Osman Zakir
// 9 / 10 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercise 7
// Exercise Specifications:
/**
 * Write a program that reads characters from cin into an array that you
 * allocate on the free store. Read individual characters until an exclamation
 * mark (!) is entered. Do not use a std::string. Do not worry about memory exhaustion.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>

int main()
{
	std::cout << "Please enter some characters; enter a '!' to stop\n";
	for (char *str = new char[32737]; std::getline(std::cin, std::string(str), '\n') && *str != '!';)
	{
		int i = 0;
		std::cout << str[i];
		++i;
	}
	std::cout << '\n';
	keep_window_open();
}


Why is it saying it's wrong?
It is complaining because you are creating a temporary string and asking for a function that fills that temporary. Doing that is pointless, so no such function was ever created — it doesn’t exist.

This is indicative of the most significant issue: even if your program compiled it wouldn’t work. The str object only initializes the string. The string itself will maintain its own copy of the content of str. getline() would modify that temporary, which is discarded immediately after it terminates, leaving you with uninitialized content in str: it will be totally unpredictable whether or not *str has any specific value.

Finally, you are violating the instructions:
Do not use a std::string.
The exercise specifically asks you to "read individual characters". Use std::cin.get(), and keep track of the current append index in str. Don’t forget to terminate the string with a null character when done getting input!

Hope this helps.
Yeah, that helped. Thanks.

By the way, is 32737 a good number? What would be a way to make sure I can continue reading characters into the string until an exclamation mark is entered? I might need a bigger string than that allows 32737 characters.
It is an exercise in the book; no error checking is required; it is unlikely that any input will exceed 100 characters or so. (That is, don't type anything more than N-2 characters before you type an exclamation mark.)

In any actual program released into the wild you would want to manage the input such that the input array is able to be reallocated as necessary, or to refuse to read more input than you have room to store. In C you would have to manage these considerations yourself. In C++, you can use std::string to do it for you.

The exercise isn't about memory management, its about character input and iterating over an array...

I would imagine better ways to teach these two concepts, but C-language textbooks have kind of followed this format for ages, so we have to put up with it...
closed account (48T7M4Gy)
I protected against memory exhaustion.

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
#include <iostream>

int main()
{
    size_t limit = 50;
    char* array = new char[limit];
    
    char ch;
    size_t length = 0;
    
    while(
          std::cout << "Pls enter a character ( ! to end ): "
          && std::cin >> ch
          && ch != '!'
          && length < limit
          )
    {
        array[length] = ch;
        ++length;
    }
    
    std::cout << array << '\n';
    
    delete[] array;
    
    return 0;
}


Pls enter a character ( ! to end ): r
Pls enter a character ( ! to end ): i
Pls enter a character ( ! to end ): c
Pls enter a character ( ! to end ): e
Pls enter a character ( ! to end ): !
rice
Program ended with exit code: 0
Thanks for this. But because the exercise says to not worry about memory exhaustion, I think I really won't worry about it for this program.

Anyway, Exercise 8 say to use a std::string to do the same thing. I'm trying it now and will post the code later. Maybe in another thread (unless it's okay to post it in this thread). For now, here's my code for Exercise 7:
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
// Osman Zakir
// 9 / 10 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercise 7
// Exercise Specifications:
/**
 * Write a program that reads characters from cin into an array that you
 * allocate on the free store. Read individual characters until an exclamation
 * mark (!) is entered. Do not use a std::string. Do not worry about memory exhaustion.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>

int main()
{
	std::cout << "Please enter some characters; enter a '!' to stop\n";
	int i = 0;
	for (char *str = new char[32737]; std::cin.get(str[i]) && str[i] != '!';)
	{
		std::cout << str[i];
		++i;
	}
	std::cout << '\n';
	keep_window_open();
}
Using a for() loop for this exercise is really a poor choice, a while loop would be a better choice.

Also you have created a memory leak because you failed to delete the manually allocated memory. And with the current structure of your program you will have difficulty deleting the memory because that pointer only exists in that loop. You would be better off creating the pointer prior to the loop. You also need to insure that the bounds of the array is never exceeded, no matter how big you make your array. And remember that since you terminate the array with the end of string character you can't use print the array as C-string. I also would expect you to print the array after the data entry loop not print each individual character in the data entry loop. I also wouldn't be unexpected to see you using pointer notation instead of the array[] notation, after skimming the chapter text.

Have you done the previous exercise for this chapter?
You can see in the instructions that it says to not worry about memory exhaustion/memory leak, right? And yes, I did do the exercise before this one. That one also said to deliberately cause a memory exhaustion and check how much memory you can allocate before new fails.
You can see in the instructions that it says to not worry about memory exhaustion/memory leak, right?

Memory exhaustion is not the same as memory leaks. The instructions don't mention anything about memory leaks, so I would assume that you are expected to properly delete the memory you allocate, which is impossible with your code.

#Edit:
The instructions also don't state that you don't need to worry about accessing your array out of bounds. When dealing with C-style arrays you need to always be concerned about accessing the array out of bounds. This exercise is, IMO, really about showing some of the difficulties you face when you use arrays instead of one of the standard containers.

Last edited on
In Exercise 6's specs, it says:

This chapter does not say what happens when you run out of memory
using new . That’s called memory exhaustion.


So that's different from a memory leak? If so, then yeah, I'll go ahead and use delete[].

By the way, here's my code for Exercise 8 as well, so I can have it looked as well:
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
// Exercise Specifications:
/**
 * Do exercise 7 again, but this time read into a std::string rather than to
 * memory you put on the free store (string knows how to use the free store
 * for you).
 */
// Note: Exercise 7 Specifications:
/**
 * Write a program that reads characters from cin into an array that you
 * allocate on the free store. Read individual characters until an exclamation
 * mark (!) is entered. Do not use a std::string. Do not worry about memory exhaustion.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <string>

int main()
{
	std::cout << "Please enter some characters; enter a '!' to stop\n";
	std::string words;
	words.resize(words.capacity() + 1);
	std::size_t i = 0;
	char ch;
	while (std::cin.get(ch) && ch != '!' && i < words.capacity())
	{
		words[i] = ch;
		++i;
	}
	std::cout << words << '\n';
	keep_window_open();
}


For Exercise 7, I'm getting some weird characters after the characters I'd entered are printed out. I'm guessing some weird characters are making it into the string, but I don't know how to fix this.

And how do I check for whether the array index is going out of bounds in this program?

For Exercise 7 output:

Please enter some characters; enter a '!' to stop
Hello, world!
Hello, world══════════════════════════════════════²²²²Pò"tT~k
Please enter a character to exit
k
Press any key to continue . . .


The output for the code for Exercise 8 is fine.
Last edited on
So that's different from a memory leak?

Yes.


For Exercise 7, I'm getting some weird characters after the characters I'd entered are printed out. I'm guessing some weird characters are making it into the string, but I don't know how to fix this.

You need to post your current code. You do realize that you need to properly terminate that array of char before you can treat is as a string right?


std::string words;
words.resize(words.capacity() + 1);

What does words.capacity() return? Since the string is empty() at this time it could return some really low value, even zero.

while (std::cin.get(ch) && ch != '!' && i < words.capacity())

Again what do you think that words.capacity() is really going to do for you? Why are you even worried about the capacity of a std::string?
 
	words[i] = ch;

Wouldn't it just be better to add the character to the string?

Perhaps something more like:
1
2
3
4
5
6
7
	std::string words;
        char ch;
	while (std::cin.get(ch) && ch != '!')
	{
		words += ch;
	}


Why are you #including <iostream> and <string> doesn't that book specific header already #include those files?

I'm not using that header anymore because it said I wouldn't need it after Chapter 10. "cust_std_lib_facilities.h" is a custom header based on it.

I tried to do "words[i] = ch" before in that context, but I kept getting an "out_of_bounds" exception. So I decided to increase the string's capacity and then add characters to it. Just to be safe.
It seems you don't understand the differences between size and capacity.
Have a look at the reference also about resize and reserve
http://www.cplusplus.com/reference/string/string/
closed account (48T7M4Gy)
I didn't protect against memory exhaustion this time:

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

int main()
{
    std::string array;
    
    char ch;
    
    while(
          std::cout << "Pls enter a character ( ! to end ): "
          && std::cin >> ch
          && ch != '!'
          )
    {
        array += ch;
    }
    
    std::cout << array << '\n';
    
    return 0;
}

Pls enter a character ( ! to end ): r
Pls enter a character ( ! to end ): i
Pls enter a character ( ! to end ): c
Pls enter a character ( ! to end ): e
Pls enter a character ( ! to end ): !
rice
So I have to use reserve() to adjust the capacity? And it says that the capacity is the size of the overall storage. That would be bigger than the current size of the string (returned by string::length()), right? That's also what I was thinking before. But I ended up not using reserve().

Anyway, I tried to make a dynamically resizable array of chars, but right now it hasn't worked. Here's the code:
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
// Osman Zakir
// 9 / 10 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercise 7
// Exercise Specifications:
/**
 * Write a program that reads characters from cin into an array that you
 * allocate on the free store. Read individual characters until an exclamation
 * mark (!) is entered. Do not use a std::string. Do not worry about memory exhaustion.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>

int main()
{
	std::cout << "Please enter some characters; enter a '!' to stop\n";
	std::size_t capacity = 50;
	char *str = new char[capacity];
	char ch;
	std::size_t i = 0;
	while (std::cin.get(ch) && ch != '!' && i < capacity)
	{
		str[i] = ch;
		if (i == capacity)
		{
			str = new char[capacity * 2];
		}
		++i;
	}
	str[i] = '\0';
	std::cout << str << '\n';
	delete[] str;
	keep_window_open();
}


Of course, the part where I'm trying to grow it is here:
1
2
3
4
if (i == capacity)
{
	str = new char[capacity * 2];
}


How do I fix it to make it work?
Last edited on
1
2
3
4
if (i == capacity)
{
	str = new char[capacity * 2];
}

That is overly simplified.

Roughly speaking, you need to allocate a separate char array with the required larger size. Copy all the characters from str to the newly-allocated array. delete [] str. Set str to point to the new buffer. Make sure capacity contains the current size.

There are a few pitfalls, you need to do things in the correct sequence. For example at present the line str[i] = ch; is done too soon, when the full capacity is reached, that will attempt to write beyond the allocated memory block. Also the while loop condition && i < capacity causes the loop to end instead of executing the code to resize the str buffer. You could remove that.
I tried to do "words[i] = ch" before in that context, but I kept getting an "out_of_bounds" exception.

Since the string is empty an out_of_bounds exception is the expected result (it appears that you're still using part of that book supplied header after all). That's why I asked why not just add the character to the string. By adding the single character to the std::string you are letting the std::string do it's job of managing memory, increasing it's size when necessary. Do you understand how you add a single character to a std::string?

This is the header I'm using:
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef CUST_STD_LIB_FACILITIES_H
#define CUST_STD_LIB_FACILITIES_H

#include <iostream>
#include <string>

int randint(int min, int max);
void error(const std::string& s, const std::string& s2);
void error(const std::string& s);
void keep_window_open();
void keep_window_open(std::string s);

#endif 


And here is its .cpp 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "cust_std_lib_facilities.h"
#include <iostream>
#include <chrono>
#include <stdexcept>
#include <random>
#include <string>

int randint(int min, int max) 
{ 
	using namespace std;

	auto seed = chrono::system_clock::now().time_since_epoch().count();
	static default_random_engine ran(seed);
	return uniform_int_distribution<>{min, max}(ran); 
}

void keep_window_open()
{
	using namespace std;
	cin.clear();
	cout << "Please enter a character to exit\n";
	char ch;
	cin >> ch;
	return;
}

void keep_window_open(std::string s)
{
	using namespace std;
	if (s == "") return;
	cin.clear();
	cin.ignore(120, '\n');
	for (;;) {
		cout << "Please enter " << s << " to exit\n";
		string ss;
		while (cin >> ss && ss != s)
			cout << "Please enter " << s << " to exit\n";
		return;
	}
}

void error(const std::string& s)
{
	using namespace std;
	throw runtime_error(s);
}

void error(const std::string& s, const std::string& s2)
{
	error(s + s2);
}


So yeah, I took some stuff from the book's supplied header, but I didn't use any of the [] operator access functions from that header.

Anyway, I'll make the suggested change. For exercise 7, as well (thanks, Chervil).

Edit: @Chervil: It still didn't work. What did I do wrong?
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
// Osman Zakir
// 9 / 10 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercise 7
// Exercise Specifications:
/**
 * Write a program that reads characters from cin into an array that you
 * allocate on the free store. Read individual characters until an exclamation
 * mark (!) is entered. Do not use a std::string. Do not worry about memory exhaustion.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <cstring>

int main()
{
	std::cout << "Please enter some characters; enter a '!' to stop\n";
	std::size_t capacity = 50;
	char *str = new char[capacity];
	char ch;
	std::size_t i = 0;
	while (std::cin.get(ch) && ch != '!')
	{
		str[i] = ch;
		if (i == capacity)
		{
			char *new_str = new char[capacity * 2];
			delete[] str;
			strcpy(str, new_str);
			delete[] new_str;
		}
		++i;
	}
	str[i] = '\0';
	std::cout << str << '\n';
	delete[] str;
	keep_window_open();
}
Last edited on
Edit: @Chervil: It still didn't work. What did I do wrong?

Several things. One thing which stands out is there are too many deletes, at both line 29 and line 31 you delete both the old and the new arrays.

You didn't store the updated value of capacity.

Also, deleting the array at line 29 when you still need to access it at line 30 doesn't make sense. The source and destination in the strcpy() are the wrong way round.

Also, strcpy() depends on the array having a null terminator, which can't be the case, because it isn't added until line 35.

I think the code should look something like this. Note the sequence in which things take place. First, the line str[i] = ch; needs to be moved, to avoid writing outside the boundary of the buffer. Also I used memcpy() instead of strcpy().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    while (std::cin.get(ch) && ch != '!')
    {

        if (i == capacity)                        // buffer is full
        {
            capacity = capacity * 2;              // set value of increased capacity.
            
            char *new_str = new char[capacity];   // allocate new buffer
            
            memcpy(new_str, str, i);              // copy all characters from old to new
            
            delete [] str;                        // done with old buffer, delete it
            str = new_str;                        // point to new buffer
        }
        
        str[i] = ch;                              // NOW ready to copy the character
        ++i;                                      // and increment position
    }
Last edited on
It still didn't work.

Why didn't it work? What didn't work? You need to ask specific questions.

How many characters are you trying to add to the string?

Why are you trying to insert characters into the string before you check that the string is large enough?

Why are you deleting the memory for both strings in your if statement?

Have you read the documentation for strcpy()?

Do you realize that you can't use strcpy() with an array of char, strcpy() requires two C-strings?

Do you understand the difference between an array of char and a C-string?


Pages: 12