"no matching function calling for getline" error

Pages: 12
Ah, yeah, I get it now. Thanks, you two. I'll fix it.

Edit: Alright, done. Both exercises.
Last edited on
I suggest you post the code for your latest attempts so you can get verification that your methods are indeed working since you had so many "errors" in your last attempts.

closed account (48T7M4Gy)
A good enough reason to use <string>'s :

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

int main()
{
    size_t limit = 1; // just a single character!
    
    char* array = new char[limit];
    
    char ch;
    size_t length = 0;
    
    while(
          std::cout << "Pls enter a character ( ! to end ): "
          && std::cin >> ch
          && ch != '!'
          )
    {
        array[length] = ch;
        ++length;
        
        // RESIZE array
        if(length >= limit)
        {
            char *temp = new char[limit *= 2];
            temp = array;
        }
    }
    
    array[length] = '\0'; // terminating character
    std::cout << length << " characters and " << array << " is the C-string\n";
    
    delete[] array;
    
    return 0;
}


Pls enter a character ( ! to end ): a
Pls enter a character ( ! to end ): s
Pls enter a character ( ! to end ): d
Pls enter a character ( ! to end ): f
Pls enter a character ( ! to end ): g
Pls enter a character ( ! to end ): h
Pls enter a character ( ! to end ): !
6 characters and asdfgh is the C-string
Program ended with exit code: 0
Last edited on
Hmm, seems overly complex to me. Allocating and copying two separate arrays where only one is needed doesn't seem to add any value.

32
33
34
35
36
37
38
39
            array = nullptr;
            
            array = new char[new_limit];
            for(size_t i = 0; i < limit; ++i)
                array[i] = temp[i];
            
            delete [] temp;
            temp = nullptr;

could be simply:
 
            array = temp;

I forgot about having the deleted pointers pointing to null. I should do that, right? Anyway, for now, this is what I have:
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
// 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 != '!')
	{
		if (i == capacity)
		{
			capacity *= 2;
			char *new_str = new char[capacity];
			memcpy(new_str, str, i);
			delete[] str;
			str = new_str;
		}
		str[i] = ch;
		++i;
	}
	str[i] = '\0';
	std::cout << str << '\n';
	delete[] str;
	keep_window_open();
}


and:
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
// Osman Zakir
// 9 / 11 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 17 Exercise 8
// 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;
	char ch;
	while (std::cin.get(ch) && ch != '!')
	{
		words += ch;
	}
	std::cout << words << '\n';
	keep_window_open();
}


@jlb: I'm sorry. The reason I was having trouble like that is probably because I forgot about that stuff. The difference between a regular array of chars and a C-string is that the latter is terminated by a '\0' character (the null-terminating zero). And the way to grow an array dynamically I learned in an online CS class and I did attempt it before in exercise 7, but I didn't do it correctly. I searched on the net and found someone saying to just do <name_of_C-string> = new char[new_size];. Either I misunderstood or that guy was dead wrong. Sorry about believing something like that. I guess I had a brain-fart.

By the way, anyone on here who's done the exercises from this book who could help with one or two exercises from Chapter 16? I'm having trouble there still. Thanks in advance. I can't post the code in a thread on here since it'd make the post too long, though, so I can only email someone the code as an attachment (but I don't know anyone's email address on here).
The reason I was having trouble like that is probably because I forgot about that stuff.

But the reason you probably forgot about that stuff is because you don't seem to experiment with the code you are given so that you really understand the problems. Instead of just taking the code from the multiple forums you seem to be using and pasting it into your program you need to understand what is happening. To do this you need to do other similar programs that involve the same principles. And remember that these exercises build on the previous exercises, so you really need to understand the concepts before moving on.

Your current code for the C-string version seems to be using code copied from one of Cervil's posts, do you really understand the difference between your broken code and the code that you're now using? Could you modify your current code to be able to use strcpy() instead of memcpy()?

I think I get it.

The function memcpy() copies the contents of the memory address in the second argument to the one in the first argument by "size" bytes of memory. It doesn't require a null-terminated array of chars for either of the first two arguments. The function strcpy() is similar except it requires just the destination C-string and the source C-string as the first and second arguments, and of course they have to be actual C-strings (i.e. null-terminated). I don't think I can use strcpy() in my code since it makes sense to only add the null-terminator on line 36. It might create problems if I try to add it within the loop.

The reason to take out the && i < capacity part of the loop condition was that it'd have made the loop stop before the array could be reallocated. It would only be good to leave that there if I didn't want to make the C-string grow dynamically (which really seems like overdoing the exercise, since exercise 10 asks to look at the solution for exercise 7 and see how I'd get the array to overflow; it's already too late for that because I've already effectively fixed the problem that would've made it overflow).
I don't think I can use strcpy() in my code since it makes sense to only add the null-terminator on line 36. It might create problems if I try to add it within the loop.

Yes in your present code you will have to make changes so you could add the terminator, but adding the terminator in the loop is possible as long as you stay within the bounds of the array.

it's already too late for that because I've already effectively fixed the problem that would've made it overflow

No, Cervil fixed the problem, you just copied his code.

Well, yeah, but I do pretty much understand what to do as well. Though I'll have to think about how to add the null-terminator within the loop.
The reason I was having trouble like that is probably because I forgot about that stuff.
The problem is probably that you really can't use this kind of code in real world scenarios.
"What you don't use, you will lose."
I don't understand the point of these exercises, I also don't understand why this book gets recommended here by the experts here in the forum.
These exercise are like teaching a cook how to build a oven in case the real one breaks down.
IMHO it would make much more sense if people would learn to use the STL to built apps or games they would use.
He probably just included these exercises to show his readers that the STL is better. Like, for example, making drills to illustrate the difference between a std::vector and a built-in array. And exercises 7, 8 and 10 were meant to show the difference between a C-string and a std::string.

Anyway, I tried to null terminate the string within the loop. I think I have two null terminators now, but I don't get how to take out the second one if that's the case. And if that's the case, why do I have weird characters show up after the string when it should've ended already?

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
52
// 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 + 1];
	char ch;
	std::size_t i = 0;
	while (std::cin.get(ch) && ch != '!')
	{
		if (i == capacity)
		{
			capacity *= 2;
			char *new_str = new char[capacity + 1];
			str[i] = '\0';
			strcpy(new_str, str);
			delete[] str;
			str = new_str;
		}
		str[i] = ch;
		++i;
	}
	for (std::size_t i = 0, n = strlen(str); i < n; ++i)
	{
		int null_count = 0;
		if (str[i] == '\0')
		{
			++null_count;
		}
		if (null_count > 1)
		{
			// TODO: take out the second null-terminator and keep the first
		}
	}
	std::cout << str << '\n';
	delete[] str;
	keep_window_open();
}
Last edited on
I don't understand the point of these exercises, ...
These exercise are like teaching a cook how to build a oven in case the real one breaks down.
IMHO it would make much more sense if people would learn to use the STL to built apps or games they would use.

In the case of these three exercises the point appears to be an introduction to C-strings and the related pointer problems. IMO, it appears to be a concrete example of problems you will face if you use C-strings and the benefits you will gain by using C++ strings instead.

I also don't understand why this book gets recommended here by the experts here in the forum.

IMO, this book is adequate when used in a structured learning environment where you have access to knowledgeable instructors that are willing to assist individuals and can "see" when someone is "lost". However trying to use the book as the primary source to learn to program can be difficult for someone who is unable to properly research problems, and the reliance on forums as primary research apparatus compounds the problems.

Anyway, I tried to null terminate the string within the loop. I think I have two null terminators now, but I don't get how to take out the second one if that's the case. And if that's the case, why do I have weird characters show up after the string when it should've ended already?

Yes, you add a null terminator at line 29:
 
    str[i] = '\0';

But it is almost immediately overwritten with a different character at line 34:
 
    str[i] = ch;

That means there is no null terminator present at all after the end of user input. You would need to add one later, just like in your previous code.

Also, the code to remove the second null terminator cannot succeed, strlen() will identify the end of the string at the first null. Actually, you can remove that code, it is trying to solve the wrong problem. You have too few terminators, not too many.
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
/**
 * 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 <iostream>
#include <memory>
#include <utility>

// allocate a larger buffer, twice the size of the old buffer
// copy the contents of the old buffer into it and delete the old buffer
// the unused portion at the end of the new buffer contains zeroes
// return a pair consisting of the pointer to the new buffer and its capacity. 
std::pair< char*, std::size_t > resize( char* old_buf, std::size_t old_buff_sz )
{
    std::size_t new_buff_sz = old_buff_sz * 2 ;
    if( new_buff_sz < 32 ) new_buff_sz = 32 ;

    char* new_buf = new char[new_buff_sz] {} ; // allocate a zero-filled buffer
    std::uninitialized_copy_n( old_buf, old_buff_sz, new_buf ) ;

    delete[] old_buf ;
    return { new_buf, new_buff_sz } ;
}

int main()
{
    std::cout << "Please enter some characters; enter a '!' to stop\n";

    auto pair = resize( nullptr, 0 ) ;
    char* str = pair.first ;
    std::size_t capacity = pair.second ;

    std::size_t sz = 0;
    char ch ;
    while( std::cin.get(ch) && ch != '!' ) // note: get() won't skip white space
    {
        if( sz == (capacity-2) ) // one extra for the null character at the end
        {
            pair = resize( str, capacity ) ;
            str = pair.first ;
            capacity = pair.second ;
        }
        str[sz++] = ch ;
    }

    std::cout << "\n\n" << str << '\n' ;
    delete [] str ;
}

http://rextester.com/DBBQ95587
Okay, got 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
// 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 + 1];
	char ch;
	std::size_t i = 0;
	while (std::cin.get(ch) && ch != '!')
	{
		if (i == capacity)
		{
			capacity *= 2;
			char *new_str = new char[capacity + 1];
			str[i] = '\0';
			strcpy(new_str, str);
			delete[] str;
			str = new_str;
		}
		str[i] = ch;
		++i;
	}
	str[i] = '\0';
	std::cout << str << '\n';
	delete[] str;
	keep_window_open();
}


@JLBorges: Thanks for that, too.
That should work but you can eliminate the need to do the '\0' assignment in two places by placing it in your loop right after the ++i.
I'll still need to do it once before the call to strcpy() either way, though, right?
Last edited on
As long as the initial capacity is greater than zero if you do the '\0' assignment right before the end of the while() loop you are doing the assignment before the strcpy(). Follow the logic for yourself to verify.



Yeah, thanks. Done.
Topic archived. No new replies allowed.
Pages: 12