I'm reading yummy recipes from a line made of different substrings divided by ; in this order:
Recipe index (R1)
Number to be cooked (1)
Recipe name (Ensalada Mixta)
Ingredients and their quantity (Lechuga 200;...)
The first three work like a charm, you can see they are stored in the data array and printed in the printf block. The problem comes reading the rest. The reader iterator reads through the line perfectly but doesn't stop at the end, so it add rubbish values to the pair and throws a segfault. Here's the output from this MRE:
:: R1
:: 1
:: Ensalada Mixta
-> Lechuga 200
-> Tomate 50
-> Pepino 50
-> Cebolla 50
-> Aceite Oliva 5
-> Vinagre De Vino 10
-> Sal 1
[1] 85313 segmentation fault (core dumped)
The loop should stop after Sal 1, so what am I doing terribly wrong? Here's the code:
#include <cmath>
#include <list>
#include <string>
#include <utility>
#include <cstdio>
using namespace std;
int main () {
string line = "R1;1;Ensalada Mixta;Lechuga 200;Tomate 50;Pepino 50;Cebolla 50;Aceite Oliva 5;Vinagre De Vino 10;Sal 1";
list<pair<string, unsigned> > ings;
string recipe_data[3];
string::const_iterator reader = line.cbegin();
//Lectura del código, plato y ing_name de la receta
for (int i = 0; i < 3; ++reader) {
if (*reader != ';')
recipe_data[i].push_back(*reader);
else
++i;
}
printf(":: %s\n", recipe_data[0].c_str());
printf(":: %s\n", recipe_data[1].c_str());
printf(":: %s\n", recipe_data[2].c_str());
/*
* This is the problematic loop. The problem is in the while boolean
* expression, which always evaluates to false.
*/
while (reader != line.cend()) {
string ing_name = "";
unsigned ing_quantity = 0;
while (*reader != ';' && reader != line.cend()) {
ing_name += *reader;
++reader;
}
string::reverse_iterator it = ing_name.rbegin();
for (int i = 0; *it != ' '; i++) {
char c[1] = {*it};
ing_quantity += atoi(c) * pow(10, i);
++it;
ing_name.pop_back();
}
ing_name.pop_back();
pair<string, unsigned> ing(ing_name, ing_quantity);
ings.push_back(ing);
printf("-> %s %d\n", ing.first.c_str(), ing.second);
++reader;
}
}
Here's gdb output using a breakpoint on the very last ++reader line:
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Tomate", second = 50}
(gdb)
Continuing.
-> Pepino 50
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Pepino", second = 50}
(gdb)
Continuing.
-> Cebolla 50
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Cebolla", second = 50}
(gdb)
Continuing.
-> Aceite Oliva 5
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Aceite Oliva", second = 5}
(gdb)
Continuing.
-> Vinagre De Vino 10
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 59 ';'
2: line.cend() = 0 '\000'
3: ing = {first = "Vinagre De Vino", second = 10}
(gdb)
Continuing.
-> Sal 1
Breakpoint 1, main () at so.cpp:52
52 ++reader;
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb) n
47 pair<string, unsigned> ing(ing_name, ing_quantity);
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb)
29 string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
(gdb)
28 while (reader != line.cend()) {
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
(gdb)
29 string ing_name = "";
1: reader = 0 '\000'
2: line.cend() = 0 '\000'
3: ing = {first = "Sal", second = 1}
As you can see, it shouldn't have re-entered the loop since the iterator and cend() are equal, right?
The inner while increments until either you find ; or cend and in both cases you continue. Only on the next iteration you stop because reader != line.cend() is false but thats already too late.
Also you have to first check if you are at the end, and only then dereference reader:
while (reader != line.cend() && *reader != ';') {
ing_name += *reader;
++reader;
}
if (reader == line.cend()) break;
Related
I follow others' guides to rewrite my string split function.
#include<string>
#include<list>
#include<optional>
#include<malloc.h>
#include<string_view>
#include<iostream>
#include<vector>
#include "include/common.h"
using std::list;
using std::string;
using std::optional;
using std::vector;
using std::string_view;
/* there not use optional is better cuz list.length == 0 repr that */
/*
#brief: split string by substring
*/
vector<string_view> split(string content, string_view delim_str) {
size_t tail_pos = 0;
size_t head_pos = std::string::npos;
vector<string_view> str_view_vec;
while((head_pos = content.find(delim_str, tail_pos))
!= std::string::npos)
{
DBG("tail_pos = %zu, head_pos = %zu", tail_pos, head_pos);
str_view_vec.emplace_back(&content[tail_pos], head_pos - tail_pos);
tail_pos = head_pos + delim_str.length();
}
if(tail_pos != content.length() - 1) {
str_view_vec.emplace_back(&content[tail_pos], content.length() - tail_pos);
}
return str_view_vec;
}
int main() {
string s("123 12312 123213a as dasd as asd");
std::cout << string_view("asdasd 123") << std::endl;
vector<string_view> l = split(s, string_view(" "));
for(const auto &i : l) {
std::cout << i << std::endl;
}
}
then compile and print:
❯ clang -o String String.cpp -g -std=c++17 -I../ -lstdc++; ./String
asdasd 123
[x] split(), String.cpp:49 : tail_pos = 0, head_pos = 3
[x] split(), String.cpp:49 : tail_pos = 4, head_pos = 9
[x] split(), String.cpp:49 : tail_pos = 10, head_pos = 17
[x] split(), String.cpp:49 : tail_pos = 18, head_pos = 20
[x] split(), String.cpp:49 : tail_pos = 21, head_pos = 25
[x] split(), String.cpp:49 : tail_pos = 26, head_pos = 28
#S
a
as
dasd
as
asd
This result is so weird cuz it doesn't print any chars in 123 12312 123213a but prints three lines of random chars;
I use lldb to verify the return value and found it seems ok;
* thread #1, name = 'String', stop reason = breakpoint 1.1
frame #0: 0x00000000004027f8 String`split(content=error: summary string parsing error, delim_str=(_M_len = 1, _M_str = " ")) at String.cpp:56:5
53 if(tail_pos != content.length() - 1) {
54 str_view_vec.emplace_back(&content[tail_pos], content.length() - tail_pos);
55 }
-> 56 return str_view_vec;
57 }
58 int main() {
59
(lldb) p str
Available completions:
str_view_vec -- vector<basic_string_view<char, char_traits<char> >, allocator<basic_string_view<char, char_traits<char> > > > &
struct
(lldb) p str_view_vec
(std::vector<std::basic_string_view<char, std::char_traits<char> >, std::allocator<std::basic_string_view<char, std::char_traits<char> > > >) $0 = size=7 {
[0] = (_M_len = 3, _M_str = "123 12312 123213a as dasd as asd")
[1] = (_M_len = 5, _M_str = "12312 123213a as dasd as asd")
[2] = (_M_len = 7, _M_str = "123213a as dasd as asd")
[3] = (_M_len = 2, _M_str = "as dasd as asd")
[4] = (_M_len = 4, _M_str = "dasd as asd")
[5] = (_M_len = 2, _M_str = "as asd")
[6] = (_M_len = 3, _M_str = "asd")
}
(lldb) q
So I want to figure out where these weird chars come from and why alphabetic lines are normal only digital lines are not print well.
Change this
vector<string_view> split(string content, string_view delim_str) {
to this
vector<string_view> split(const string& content, string_view delim_str) {
Your string views are 'pointing' at content which is destroyed when the split function exits. Using a reference avoids this.
If you want to avoid this whole issue, then use strings instead of string views. String views don't work independently of the string they view.
Is there a gdb command that does what info locals does but automatically (i.e after every step or breakpoint)? I find info locals to be very essential, but I would much rather not have to type it everytime. It would be a bummer if something like that is not implemented.
Also I'm not looking to "watch" or "display" a specific variable or two. Display all, everytime, that's what I'm looking for.
Display all, everytime, that's what I'm looking for.
(gdb) define hook-stop
info locals
end
Example:
// foo.c
int foo()
{
int z = 1;
int zz = 2;
int zzz = 3;
return z + zz + zzz;
}
int main()
{
int x = 42;
int y = 24;
foo();
return x;
}
gcc -g foo.c && gdb -q ./a.out
(gdb) define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>info locals
>end
(gdb) start
Temporary breakpoint 1 at 0x1159: file foo.c, line 11.
Starting program: /tmp/a.out
x = 0
y = 0
Temporary breakpoint 1, main () at foo.c:11
11 int x = 42;
(gdb) n
x = 42
y = 0
12 int y = 24;
(gdb) n
x = 42
y = 24
13 foo();
(gdb) s
z = 21845
zz = 1431654784
zzz = 0
foo () at foo.c:3
3 int z = 1;
(gdb) n
z = 1
zz = 1431654784
zzz = 0
4 int zz = 2;
(gdb) n
z = 1
zz = 2
zzz = 0
5 int zzz = 3;
(gdb) n
z = 1
zz = 2
zzz = 3
6 return z + zz + zzz;
(gdb) n
z = 1
zz = 2
zzz = 3
7 }
(gdb)
x = 42
y = 24
main () at foo.c:14
14 return x;
(gdb) q
Documentation here.
I am just starting out in C++.
I am writing a console application, to "read in" an .evt file (custom, not to be confused with Event viewer files in Windows) and its contents but now I need to write a method to.
a) Store each block of 'EVENT X' including but also ending at 'END'.
b) Make the contents of each block searchable/selectable.
If the content wasn't so 'wildly' varied, I would be happy to put this into some SQL table or experiment with an array but I don't know a starting point to do this as the number of 'fields' or parameters varies. The maximum number of lines I have seen in a block is around 20, the maximum number of parameters per line I have seen is around 13.
I'm not asking for an explicit answer or the whole code to do it although it is welcome, just a generic sample of code to get started that might be appropriate.
This my function to just load the data as it is.
void event_data_loader()
{
string evt_data;
string response2;
cout << "You have chosen to Create/Load Soma events\n\n";
ifstream named_EVT("C:/evts/1.evt");
while (getline(named_EVT, evt_data))
{
// Output the text from the file
cout << evt_data << "\n"; // Iterate out each line of the EVT file including spaces
//name_EVT.close();*/
}
cout << "Does the output look ok?(Y/N)";
cin >> response2;
if (response2 == "Y")
{
// Vectors? Dynamic array? to re-arrange the data?
}
}
The files themselves have content like this. I know what most of the functions do, less so all of the parameters. For some reason putting this on the page it puts them into a single line.
EVENT 01
A CHECK_HUMAN
A CHECK_POSITION 1 250 90 350 90
E BBS_OPEN 1 0
END
EVENT 02
E SELECT_MSG 336 363 314 337 03 338 12 -1 -1
END
EVENT 03
E RUN_EVENT 761
E RUN_EVENT 04
E RUN_EVENT 05
END
EVENT 761
A EXIST_ITEM 373 1
E SELECT_MSG 857 315 762 316 763 -1 -1 -1 -1
E RETURN
END
EVENT 762
A EXIST_ITEM 373 1
E ROB_ITEM 373 1
E SHOW_MAGIC 6
E CHANGE_HP 1 10000
E CHANGE_MP 1 10000
E MESSAGE_NONE 858
E RETURN
END
EVENT 1862
A ABSENT_EVENT 1582
A EXIST_ITEM 1800 1
A EXIST_ITEM 1801 1
A EXIST_ITEM 1802 1
A EXIST_ITEM 1803 1
A EXIST_ITEM 1804 1
A EXIST_ITEM 1805 1
A EXIST_ITEM 1806 1
A EXIST_ITEM 1807 1
A WEIGHT 365 1854 1 1832 1 -1 1 -1 -1 -1 -1
A CHECK_ITEMSLOT 393 1854 1 1832 1 -1 1 -1 -1 -1 -1
A GENDER 1
E ADD_EVENT 1582
E MESSAGE_NONE 3237
E ROB_ITEM 1800 1
E ROB_ITEM 1801 1
E ROB_ITEM 1802 1
E ROB_ITEM 1803 1
E ROB_ITEM 1804 1
E ROB_ITEM 1805 1
E ROB_ITEM 1806 1
E ROB_ITEM 1807 1
E GIVE_ITEM 1854 1
E GIVE_ITEM 1832 1
E RETURN
END
I would do something like this:
struct Subevent {
std::string selector;
std::string name;
std::vector<int> params;
};
struct Event {
int id;
std::vector<Subevent> subevents;
};
std::vector<Event> load_events(std::istream& input_stream) {
std::vector<Event> out;
Event current_event {}; // current event being built
std::string line;
bool inside_event = false; // are we inside the scope of an event?
while (std::getline(input_stream, line)) {
// strip trailing whitespace
while (isspace(line.back())) {
line.pop_back();
}
// skip empty lines
if (line.size() == 0) {
continue;
}
// read first token (until first space)
std::stringstream ss(line);
std::string first_token;
ss >> first_token;
bool is_new_event_line = first_token == "EVENT";
bool is_end_line = first_token == "END";
if (is_new_event_line) {
// line: EVENT <id>
if (inside_event) {
// error: "not expecting new event"
// choose your own error messaging method
}
int id;
ss >> id; // read <id>
// setup new event
current_event.id = id;
inside_event = true;
}
else if (is_end_line) {
// line: END
if (!inside_event) {
// error: "unexpected END"
}
// record and clear current event
out.push_back(current_event);
inside_event = false;
current_event = Event();
}
else {
// line: <selector> <name> <params...>
// e.g.: A GENDER 1
if (!inside_event) {
// error: "unexpected property entry"
}
// read subevent
Subevent subevent {};
subevent.selector = first_token;
ss >> subevent.name;
// copy over the int params from the line
std::copy(
std::istream_iterator<int>(ss),
std::istream_iterator<int>(),
std::back_inserter(subevent.params)
);
// push back subevent
event.subevents.push_back(subevent);
}
}
return out;
}
I'm trying to make a program that print every 100K-th odd prime number until 10M using Potion, my code:
last = 3
res = (last) # create array
loop:
last += 2
prime = true
len = res length -1
i = 0
while(i<len):
v = res at(i)
if(v*v > last): break.
if(last%v == 0): prime = false, break.
i += 1
.
if(prime):
res append(last)
if(res size % 100000 == 0): last print.
if(last>9999999): break.
.
.
But this gives Segmentation fault (core dumped), I wonder what's wrong?
For reference, the working Ruby version:
res = [last=3]
loop do
last += 2
prime = true
res.each do |v|
break if v*v > last
if last % v == 0
prime = false
break
end
end
if prime
res << last
puts last if res.length % 100000 == 0
break if last > 9999999
end
end
The output should be:
1299721
2750161
4256249
5800139
7368791
8960467
and no, this is not a homework, just out of curiosity.
you found it out by yourself, great!
println is called say in potion.
And it crashed in res size.
E.g. use this for debbugging:
rm config.inc
make DEBUG=1
bin/potion -d -Dvt example/100thoddprime.pn
and then press enter until you get to the crash.
(example/100thoddprime.pn:18): res append(last)
>
; (3, 5)
[95] getlocal 1 1 ; (3, 5)
[96] move 2 1 ; (3, 5)
[97] loadk 1 5 ; size
[98] bind 1 2 ; function size()
[99] loadpn 3 0 ; nil
[100] call 1 3Segmentation fault
so size on res returned nil, and this caused the crash.
And instead of last print, "\n" print.
Just do last say.
This came from perl6 syntax, sorry :)
My bad, I forgot to change from res length -1 to res length when changing from 0 to len (i), because this syntax not recognized as a loop (failed to receive break).
last = 3
res = (last)
loop:
last println
last += 2
prime = true
len = res length
i = 0
while(i<len):
v = res at(i)
if(v*v > last): break.
if(last%v == 0): prime = false, break.
i += 1
.
if(prime):
res append(last)
if(res length % 100000 == 0): last print, "\n" print.
if(last>9999999): break.
.
.
I need some help in using GDB + Python extensions for Go.
The struct LogQuery I am trying to look into is composed as follows:
LogQuery (struct)
CommonCmd (struct)
Context (struct)
out
Globs
flagHelp
...
flagLog
...
Breakpoint 3, acme/subcmds.CmdObj (context=..., cmdName="log_query", noname=
void) at /nobackup/git/goacme/src/acme/subcmds/cmder.go:32
32 cmd = NewLogQuery(context) //debugger
(gdb) s
acme/subcmds.NewLogQuery (context=..., noname=void)
at /nobackup/git/goacme/src/acme/subcmds/log_query.go:29
29 func NewLogQuery(context context.Context) LogQuery {
(gdb) n
30 obj := LogQuery{NewCommonCmd(context), "", "", "", "", 0, "", ""}
(gdb)
31 return obj
1 - printing the object (obj) inside the constructor works. But how do I see 'obj.Globs'?
(gdb) p obj
$8 = {acme/subcmds.CommonCmd = {acme/context.Context = {out = 0, Globs =
0xf840050140}, FlagArgs = "", flagDebug = "", flagHelp = false,
flagOutput = "", flagVerbose = false, CmdName = "", debug = 0x0},
flagColl = "", flagData = "", flagDb = "", flagHost = "", flagLimit = 0,
flagLog = "", flagQuery = ""}
Returning to the caller
(gdb) n
acme/subcmds.CmdObj (context=..., cmdName="log_query", noname=void)
at /nobackup/git/goacme/src/acme/subcmds/cmder.go:40
40 if cmdName == "acme" {
Here I see the type of the object, but can't seem to be able the see anything in it
(gdb) p cmd
$9 = "(subcmds.LogQuery)0xf840052b60"
(gdb) p $dtype(cmd)
$2 = (struct cmds.Add *) 0xf840034210
(gdb) p cmd->Globs
A syntax error in expression, near `>Globs'.
(gdb) p cmd.Globs
There is no member named Globs.