so probably a silly question but i'm not very familiar with C++ so...
Then i run this code, it crash with no error code after hitting the second if in the main
#include <fstream>
#include <string>
#include "day.cpp"
#include "appointement.cpp"
using namespace std;
// Flags are placed as constants to easy access
const string mod="mod", lst="lst", rmv="rmv";
const string add="add", title="-t", date="-d";
bool ispresent (string command, string flag)
{
int pos=command.find(flag);
if (pos==-1)
{
return false;
}
else
{
return true;
}
}
int main()
{
string command;
cout << "Hi, send command:";
//this is analysed and searched for flags
cin >> command;
//if the "add" is present, create a new event (userEvent)
if (ispresent (command, add))
{
cout << "add triggered";
ofstream saveFile;
saveFile.open("/tmp/.calendar/saveFile.txt");
appointement userEvent;
// this test always fail
if (ispresent(command, title))
{
//search for "-t" to add the title to the event
cout << "-t triggered";
int flag=command.find("-t")+2;
cout << "placed after -t";
userEvent.setTitle(command.substr(flag,command.find(" ")));
cout << "title set";
// search for "-d" to add the date to the event
if (command.substr(flag,flag)==date)
{
int flag=flag+2;
userEvent.setTimeNotification(command.substr(flag+2, command.find (" ")));
}
}
}
return 0;
}
at first i thought at a bad test, but running it into gdb given me this error :
ispresent (command=<error reading variable: Cannot access memory at address 0x6a9b6f7a416ff400>,
flag=<error reading variable: Cannot access memory at address 0x3>) at main.cpp:13
I understand that there is something going with access right to the variables but i don't understand what is actually going on...
I check for similar questions here, but nobody seems to explain that is actually going on and how to fix/avoid it in the future
So after #molbdnilo pointed out, my "command" isn't actually the way it thought it was and only contain the first string in the command (each white space breaks my command in multiples strings).
So the issue is then i call the second test, it cannot work because my "command" variable is smaller than the position i tried to test, so then the program call the memory space where the continuation of the variable should be i get an memory error since this program is not allowed to use this memory space.
Related
Problem Description:
I have created a custom C++ function print() that is supposed to be pushed as a global onto a table to so the user can use the print() function to print to the debug console. This function works to some extent, however, when you try to print a string with a space in it (over one word) the function is not called at all... This has greatly confused me, as I don't know why. If I were to try and call something such as print("Hello!") the console will have "Hello!" printed to it, but if I were to try and print something such as print("Hello world!") the function will not be called at all, I know this because I have used a message box to alert when the function is called.
Additional Information:
So, the closest thing to this I could find was a question asking how to make a custom print function in C++ with the Lua C API then push it onto the global table. I can already do this, and my function works to some extent. My function isn't being pushed onto the Lua C API's global table, instead to a table that is created by me with lua_newtable(L, s);. However, I've tried it both ways and it makes no difference. This print function does not support tables nor function as of now, I'm just focused on finding out and fixing why the function can't print strings over one word. Just in case you were wondering, Lua v5.1.5 and Microsoft Visual Studio 2017 are used for this. Debug mode, x86.
Code (C++):
If anyone could help me fix this, that would be great!
#include <iostream>
#include <string>
#include <Windows.h>
#pragma comment(lib, "Lua.lib")
#include "lua.hpp"
#include "luaconf.h"
static int print(lua_State* LUASTATE)
{
MessageBoxA(NULL, "Custom print called.", "FUNCTION!", NULL);
int nargs = lua_gettop(LUASTATE);
std::string string = "";
for (int i = 1; i <= nargs; i++)
{
if (i > 1) string += " ";
switch (lua_type(LUASTATE, i))
{
case LUA_TSTRING:
string += (std::string)lua_tostring(LUASTATE, i);
case LUA_TNUMBER:
string += (int)lua_tonumber(LUASTATE, i);
case LUA_TBOOLEAN:
string += (bool)lua_toboolean(LUASTATE, i);
}
}
std::cout << string << "\n";
return 0;
}
int pushs(lua_State* LuaState)
{
luaL_openlibs(LuaState);
lua_newtable(LuaState);
lua_pushcfunction(LuaState, print);
lua_setglobal(LuaState, "print");
lua_settop(LuaState, 0);
return 0;
}
int main()
{
lua_State* ls = luaL_newstate();
lua_State* LS = lua_newthread(ls);
pushs(LS);
while (true)
{
std::cout << " ";
std::string inputo;
std::cin >> inputo;
luaL_dostring(LS, inputo.c_str());
lua_settop(LS, 0);
}
lua_close(LS);
return 0;
}
Main problem
std::cin >> inputo does not read a full line from the standard input. It just reads a single word. So when you type the following input line in your shell:
print("Hello world")
Your main loop breaks it into two separate strings:
print("Hello
world")
And these string are evaluated independently by the Lua interpreter. None of these strings are valid Lua statements, so the interpreter doesn't execute them. lua_dostring will return an error code, and let an error message on the Lua stack.
To work line by line on the standard input, you can use std::getline, which works well in a loop:
std::string line;
while (std::getline(std::cin, line)) {
// do something with line.
}
Side notes
What follows is not directly related to your bug, but look suspicious:
std::string += int (or bool) interprets the int as a single char, and append this single character to the string.
Your switch/case seems to be missing break statements.
lua_State* ls is never closed.
Im trying to get a users input using cin.get() but I dont want to limit the amount of characters that they can enter. How can I do this?
EDIT: I guess a better way to phrase this would be: How can I dynamicaly change the character array to fit the length of the users input?
This is a strange requirement for a C++ program. You can of course go the C way and simply keep on getting more memory whenever your input outgrows the currently available memory. It goes something like this (warning: code fragments ahead):
while(cin.get(c)) {
if (cur_pos == cur_len) {
cur_len = grow_charbuf(buffer, cur_len);
}
buffer[cur_pos++] = c;
}
Here, the grow function is where it gets ugly. It needs to allocate a larger piece of memory, copy the contents of the current buffer to the beginning of that, dealocate the memory occupied by the current buffer, and return the new size. For example, something along these lines:
char* new_charbuf(size_t len) {
return new char [len];
}
size_t grow_charbuf(char* buf, size_t cur_len) {
size_t new_len = cur_len * 2;
char* new_buf = new char [new_len];
// copy old buffer contents to new buffer
delete[] buf;
buf = new_buf;
return new_len;
}
And you can then use it as follows:
cur_len = 1000; // or whatever
char* buffer = new_charbur(cur_len);
// write into the buffer, calling grow_charbuf() when necessary
// and don't forget to free the memory once you are done...
// or don't free it, if the program eventually exits anyway
This is terrible code. It might work, but you should never ever do this in C++ if you can avoid it. Apart from this, I have avoided handling any error conditions or exceptions that this code might cause. It is meant just to illustrate the idea.
Managing your memory manually is a bad idea because it requires a lot of code and is not easy to get right. You can get away with less if your program has a known, limited life-span.
Don't use characters array at all. Use std::string or other standard containers.
And of cause learn to use streams.
Here an example. It reads as many characters as the user inputs until the user presses enter. As you cna see, there is no explicite buffer-size required:
/////TEST PUT ANYWHERE IN GLOBAL SCOPE
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int test()
{
//SET BP HERE AND STEP THROUGH
string line;
getline(cin,line);
std::stringstream user_input( line );
while(!user_input.eof())
{
string word;
user_input >> word;
cout << word << endl;
}
return 0;
}
static int _test = test();
/////END TEST
You need a cin.getline(). In other words you need to have a specified size of char array and use it like so:
Using cin.get()
char str[100];
char sayHello[100];
cin.get(str, 100);
// make sure to add cin.ignore() or program will terminate right before next cin().
cin.ignore();
cout << str << endl;
cin.get(sayHello, 100);
cout << sayHello;
or for cin.getline()
char input[100];
cin.ignore(); // stops the sentence from truncating.
cin.getline(input,sizeof(input));
You could also use getline() for strings like so:
string name;
getline(cin, name);
The problem is that in c++ when receiving input your cin looks for the 0 aka the space in your sentence. It then ends thinking that was the end.
So I have a list
{"ID":"55e5f0c8ace3e","nombre":"Jacqueline ","apellido":"Charlet ","sobrenombre":"","edad":"30","caracteristicas":"","comentario":"",
I need to change that list and put it in a correct way like:
ID: 55e5f0c8ace3e
Nombre: Jacqueline
Apellido: ...
etc..
Tried this:
#include <iostream>
#include <fstream>
using namespace std;
ifstream datos("datos.txt");
ofstream final("final.txt");
int main(){
char valor;
if(!datos)
{
cout << "error";
}
else
{
while(!datos.eof())
{
datos.get(valor);
if(valor == 'I' && datos.peek() == 'D')
{
cout << "I can read" << endl;
}
}
}
}
I´m trying to do this with C++, which is the correct way to do it? I´ve tried some ways, but i dont know how to read from one point to another, by this i mean read from the double comas the ID and finish on the other double comas.
Thanks in advance
Introduce a integer state variable that describes what part of file you're in. Then interpret every character in accordance with that. For example, initially it's 0. Once you encounter a ", it becomes 1 - that means you're reading a name. If state is 1, and a character is not a "", you accumulate characters in some string variable. Once you encounter a quote character and state is 1, that means the name is over. And so on.
If this is not homework, Google for a C++ JSON parser. This is a stock problem, solved a thousand times already.
Also, please don't edit the answer - place a comment instead.
Here is what I should do
making a program that reads a text file that contains encrypted message and crack it it is kind of close to substitution cipher where I should swap swap each letter back with another meaning like shifting B back to A if its being shifted by one, and try comparing shifted words by some common used words to find if 2 of the common words have been found on the shifted ones
ex: shift the word by one
check when you shifted it is there 2 common words found?
no keep going
yes means thats it stop shifting
Now this issue here which makes the program hard for me is that I do not have a key to be entered it would've been awesome if I had it.
3 issues I am having now, is in my void function it will not print anything,
the second issue is, even if I fix my issue (I know this because in my function I have added something to convert string to c_string) and the issue is it will not shift until it finds the words I am looking which I have declared in string "Common[]"
3rd issue is whenever I compile I get an error invalid conversion from const char** to char comparison between signed and unsigned integer expressions
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <ctype.h>
using namespace std;
void makeshift (string encrypt, int key)
{
for (int i = 0 ; i<encrypt.size();i++)
{
cout<<encrypt<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt.c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
}
}
int main (int argc, char* argv[])
{
// this will make me compare between encrypted message to check if it
// contains this words or not!
const char* common[]{"the","and","in","he","with","that","as","at","do"};
string encrypted; // The encrypted message gotten from file
ifstream message(argv[1]); // get file name typed by user
if(message.is_open()) // check if file is open
{
while (!message.eof()) // check if we reached end of file
{
// get the whole line in file
getline(message,encrypted);
///loop throgh it to store numbers in declared varibles
for (int i = 0 ; i < encrypted.size();i++)
{
makeshift(encrypted,i);
// here is where the error occurs which is "invalid conversion
// from const char to char
if(encrypted.find(common) != -1)
{
cout<<"found common"<<endl;
cout<<encrypted<<endl;
break;
}
}
}
}
}
Compile error
First, you say you're getting a compile error on this line:
if(encrypted.find(common) != -1)
The reason for that is because find() expects its argument to be a string, but common is an array of strings. In other words, find() can only search for one word at a time. It can't search for a whole list of words.
To fix that, you'll want to write a loop and check one word each iteration.
Shift function
Next up is the makeshift function. A couple of suggestions there.
There's no real need to call c_str(). You can change encrypted directly by modifying each encrypted[i] in the loop.
It needs to return the result. If you modify encrypted but do not return it then the caller won't see the result.
The printouts ought to be outside the loop. Presumably you just want to see the before and after results after you've decrypted the entire string.
Here's what it looks like with those issues addressed:
string makeshift (string encrypt, int key)
{
cout << encrypt << endl; // to see what is in file way to debug
for (int i = 0 ; i<encrypt.size();i++)
{
encrypted[i] -= key;
}
cout << "decrypted message is " << encryptedc << endl;
return encrypted;
}
And then you would call it as:
string decrypted = makeshift(encrypted, i);
By the way, I'm not sure if the encrypted[i] -= key; line is completely correct. My guess is you'll need to handle wraparound. Like if you subtract 3 from the letter "A" you should probably wrap around to "X", correct? If so, I'll leave that as a TODO for you.
I/O error checking
Lastly, let's talk about I/O. Specifically, this bit of code:
ifstream message(argv[1]); // get file name typed by user
if(message.is_open()) // check if file is open
{
while (!message.eof()) // check if we reached end of file
{
// get the whole line in file
getline(message,encrypted);
...
}
}
A good practice in C++ is to check the results of I/O operations (e.g. getline). After you read a line you need to check that the read actually worked. You don't want to continue on if getline() failed (say, because it hit end-of-file).
Conveniently, if you write while (getline(...)) then that'll do a whole bunch of things all at once--it'll check if the file is open, if it's at EOF, and it'll read lines and tell you if the reads were successful. That means you can replace the stuff above with a single loop:
ifstream message(argv[1]); // get file name typed by user
while (getline(message, encrypted))
{
...
}
You are passing the value of encrypted to makeshift, so whatever you do in makeshift function will not change the encrypted in main function
you have 2 solutions here:
you can either pass the pointer of encrypted to the makeshift function
void makeshift (string* encrypt, int key){
for (int i = 0 ; i<encrypt.size();i++)
{ cout<<encrypt->c_str()<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt->c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
}
}
int main (int argc, char* argv[]){
...
makeshift(&encrypted, i);
...
}
Or you can return the value of encryptedc and assign it back to encrypted in main function
string makeshift (string encrypt, int key){
for (int i = 0 ; i<encrypt.size();i++)
{ cout<<encrypt.c_str()<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt.c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
return encryptedc; //you can assign const char* to string
}
}
int main (int argc, char* argv[]){
...
encrypted = makeshift(encrypted, i);
...
}
what i'm writing is simple, well, it should be, but i'm getting this error and i don't know what else to do, my code look like this
int main()
{
char *option;
while(strcmp(option,"exit")!=0){
int opt = GetSystemDefaultUILanguage();
std::string lang;
switch(opt)
{
case 3082:
lang = "number 3082";
break;
case 1033:
lang = "number 1033";
break;
}
std::cout<<lang<<'\n';
std::cin>>option;
}
}
when i compile it there isn't errors, but when i run it, i get a this error
Project xxxx raised exception class EAccessViolation with message 'Access violation at address zzzzz'.Process stopped. Use Step or Run to continue.
EDITED:
This is my full code, now is more simple, but still the same result.
even if i try with an if/else statement it wont work, need some help here, thanks
Your program will always get an access violation because of the following lines:
char *option;
while(strcmp(option,"exit")!=0){
std::cin>>option;
You never initialize the pointer option, but then try to use it. Change your code to this:
int main()
{
std::string option;
while(option != "exit")
{
int opt = GetSystemDefaultUILanguage();
std::string lang;
switch(opt)
{
case 3082:
lang = "number 3082";
break;
case 1033:
lang = "number 1033";
break;
}
std::cout<<lang<<std::endl;
std::cin>>option;
}
}
I can't tell you the cause of the specific run-time error you're seeing, but I call tell you what's wrong with your program: hardcoded paths to user directories. Localized names are just one of a myriad of things that can go wrong with trying to guess the paths yourself.
DON'T DO THAT. Instead, read environment variables or call Shell APIs to find out where this particular user wants temporary data stored (or documents, pictures, desktop icons, etc).
Have a look at getenv("TEMP") and ShGetSpecialFolderPath
Your problem is this line:
std::cin>>option;
The variable option is declared as an uninitialized pointer to a character. Thus in the above statement, you are reading data into an unknown location.
Why do you use C style strings (char *) and C++ std::string?
You should get rid of C style strings (unless they are constant).
Try this:
#include <iostream>
#include <string>
int main(void)
{
std::string option;
do
{
std::cout << "Type exit to end program." << std::endl; // endl will flush output buffer
std::getline(cin, option); // Input a text line into "option".
} while (option != "exit"); // C-style string, used as a constant.
return 0;
}
You wrote
BlockquoteProject xxxx raised exception class EAccessViolation with message 'Access violation at address zzzzz'.Process stopped. Use Step or Run to continue.
So why don't you pause your program before crash, go to the location and put a breakpoint? If you still can't cope with that than upload your code to a filesharing server and give us the link ;)