1

Hello guys so this is my code. I could not use cin nor getline() so I had to use scanf. It reads all the values in as expected but after entering the last value it says:

free(): invalid pointer ./comp: line 8: 877 Aborted (core dumped) ./$BIN

Anyways, here is the code. Help would be appreciated.

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;


int main() {
    // n -> amount of lines of code.
    // q -> amount of queries.
    int n, q;
    cin >> n >> q;

    // Handle source code Input.
    vector<string> v(n);
    for (unsigned i = 0; i < n; ++i)
    {
        cout << "i: " << i << endl;
        scanf("%s", &v[i]);
    }
    
    return 0;
}
  • 3
    `std::string` doesn't play well with `scanf("%s` . Where on earth did this idea foster? You said, *"I could not use cin nor getline()"* - because... ? Maybe we fix *that* problem by showing what you tried in that regard rather than chasing this X rabbit down a Y hole. – WhozCraig Jul 29 '21 at 19:52
  • 2
    The `%s` format argument says a pointer to a `char` array is coming. `std::string` is a LOT more complicated than a `char` array. Also note that `scanf` is a C function. It knows nothing of C++ structures like `std::string` and will almost certainly use them incorrectly. – user4581301 Jul 29 '21 at 19:55
  • 2
    By the way, in any language, but *especially* in an error-prone language like C++, you should *always* turn the warnings as high as they'll go. In g++ and in clang, you can pass `-Wall` to the compiler to turn all warnings on. You would've gotten a warning from the compiler that explained this issue if you did. – Silvio Mayolo Jul 29 '21 at 19:58
  • @WhozCraig the reason I could not use getline(); was because of a weird bug that would make the loop loop two times before prompting me for input. So the first time I get prompted for input, i is equal to 1. Also I am a beginner so bare with me here ;D –  Jul 29 '21 at 19:58
  • 2
    In that case you likely ran into [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – user4581301 Jul 29 '21 at 19:59
  • @user4581301 dang i think thats was what I was looking for, thank you very much! Edit: dude thank you so much, it worked, God bless you man. –  Jul 29 '21 at 20:03
  • 1
    An addendum to Silvio Mayolo's comment about extra warnings, it also helps to turn up the optimization level when compiling. In order to optimize code, the compiler has to take a much closer look at the code, and that closer look may expose potential errors that the compiler otherwise misses. – user4581301 Jul 29 '21 at 20:03

2 Answers2

2

scanf is designed to work with character buffers, not strings. You probably want to use std::string (it's more intuitive and manages memory for you), so scanf is a poor fit. There's a version of getline that works with string.

std::vector<std::string> v(n);
for (int i = 0; i < n; i++) {
  cout << "i: " << i << endl;
  std::getline(std::cin, v[i]);
}
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0

The %s specifier of scanf() expects a pointer to a char[] array, not a std::string object. By reading directly into a std::string object, you are corrupting its internals.

So, you need to either:

  • read into a char[] first, then assign that to your std::string:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
    // n -> amount of lines of code.
    // q -> amount of queries.
    int n, q;
    cin >> n >> q;

    // Handle source code Input.
    vector<string> v(n);
    char buf[256];
    for (unsigned i = 0; i < n; ++i)
    {
        cout << "i: " << i << endl;
        scanf("%255s", buf);
        v[i] = buf;
        /* or:
        int len = scanf("%255s", buf);
        v[i] = string(buf, len);
        */
    }
    
    return 0;
}
  • pre-allocate the std::string's internal character buffer, then read directly into it (note, this approach is only guaranteed to work in C++11 and later, but in practice will typically work in most implementations of std::string in earlier versions, too):
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
    // n -> amount of lines of code.
    // q -> amount of queries.
    int n, q;
    cin >> n >> q;

    // Handle source code Input.
    vector<string> v(n);
    for (unsigned i = 0; i < n; ++i)
    {
        cout << "i: " << i << endl;
        v[i].resize(256);
        int len = scanf("%255s", &v[i][0]/* or: v[i].data() in C++17 and later */);
        v[i].resize(len);
    }
    
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770