Random and replacement characters in c++ output - c++

I am writing a program to reverse a string and insert random characters in between.
Here is my code:
main.cpp
#include <iostream>
#include <chrono>
#include <thread>
#include "encrypter.cpp"
using namespace std;
int main(int argc, char *argv[])
{
char message[256];
this_thread::sleep_for(chrono::milliseconds(1000));
cout << "Make sure theres no one around you" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
cout << "Enter secret message ";
cin.get(message, 256);
cout << "message encrypted" << endl;
enc(message);
return 0;
}
encrypter.cpp
#include <iostream>
#include <string>
int getRandom(int a, int b) {
return a + (rand() % static_cast<int>(b - a + 1));
}
using namespace std;
void enc(char message[256]) {
int i = 0;
int len = strlen(message);
int revlen = len - 1;
int wtpselector;
int charselector;
int encsim;
char randchar[6] = "##$%&";
char strreved[256];
char strenc[1024];
while (i < len) {
strreved[revlen] = message[i];
i++;
revlen--;
}
revlen = strlen(strreved);
len = revlen - 1;
i = 0;
encsim = 0;
while (i < revlen) {
wtpselector = getRandom(0, 4);
charselector = getRandom(0, 4);
if (wtpselector == 0) {
strenc[encsim] = strreved[i];
i++;
encsim++;
} else {
strenc[encsim] = randchar[charselector];
encsim++;
}
}
cout << strenc << endl;
}
But the output has many random characters that are not supposed to be there and are not in the program.
Like:
Input: hello world
Output: $%#$#&&d&&#%$%1%row &#$$#%&ol#%##%&1%&#$&#ehe$%%€##8#&%#$#& #%##%&¢&#%#&#$##$#%%##&%##&#&$8%#$###$#$##%&&#&##Q#$$#&¢%#% Q#\#&$##{&&&&$#¢ \ $$$$######&&&%%&&%{ $#¢v#&#&~u####%&%¢
Please help!!!

You have missed two important things:
when you declare an array it's values are not defined (whatever is in memory)
strlen counts to the first occurance of '\0' character
In order for your code to work you must initialize char arrays, which means change those two lines:
char strreved[256];
char strenc[1024];
to:
char strreved[256] = {0};
char strenc[1024] = {0};

Related

segmentation fault pushing back to vector in shared memory

I working on a program that simulates travel agents booking flights in parallel. It spins up a process for each agent and works against an array of Plane objects held in shared memory.
I'm getting a segmentation fault when I try to push a row of seats back to the plane. The method to parse the input file calls a SetSeats() method on Plane objects. Each Plane contains a vector<map<char, Seat>> (each index of the vector is a row, each key of each map is the letter of a seat on that row). When I call SetSeats() it goes fine through adding seats to the first map, i.e. the first row of seats. It throws the segfault when I try to push the map back to the seats vector.
I saw something online about pushing back custom classes to vectors needing deconstructors, so I added them to Seat.h and Plane.h.
Code for the main program:
#include <iostream>
#include <map>
#include <vector>
#incluce <string>
#include <fstream>
#include "Seat.h"
#include "Plane.h"
void ParseInputFile(ifstream &inFS, int numPlanes, int &numAgents);
int shmid;
int *timer;
int numPlanes, numAgents;
struct sembuf *ops;
Plane *sharedPlanes;
map<string, Plane*> planes;
using namespace std;
int main(int argc, char *argv[])
{
ifstream inFS;
// code to get an input file from command line arguments and get number of planes from it
// set up shared memory segment
long key = XXX; // just a long integer
int nbytes = 1024;
shmid = shmget((key_t)key, nbytes, 0666 | IPC_CREAT);
if (shmid == -1)
{
printf("Error in shared memory region setup.\n");
perror("REASON");
exit(2);
}
// initialize global variables
sharedPlanes = new Plane[numPlanes];
timer = new int;
ops = new sembuf[1];
// attached shared pointers to shared memory segment
sharedPlanes = (Plane*)shmat(shmid, (Plane*)0, 0);
timer = (int*)shmat(shmid, (int*)0, 0);
*timer = 0;
inFS.open(inputFile);
ParseInputFile(inFS, numPlanes, numAgents); // breaks in here
// the rest of main()
}
void ParseInputFile(ifstream &inFS, int numPlanes, int &numAgents)
{
string line = "";
bool foundNumberOfPlanes = false;
bool foundPlanes = false;
bool foundNumberOfAgents = false;
bool lookingForAgent = false;
bool foundAgent = false;
int planeNo = 0;
int agentNo = 0;
int opNo = 0;
map<string, Operation> ops;
vector<Request> agentRequests;
while (getline(inFS, line))
{
if (!CommonMethods::IsWhitespace(line))
{
// code to read first line
if (foundNumberOfPlanes && !foundPlanes)
{
// parse a line from the input file to get details about the plane
Plane *plane = &sharedPlanes[planeNo];
unsigned int rows = xxx; // set based on the plane details
unsigned int seatsPerRow = xxx; set based on the plane details
plane->SetSeats(rows, seatsPerRow); // this is the method where I get the seg fault
// finish defining the plane
continue;
// the rest of the method
}
}
}
}
Code for Plane.h:
#pragma once
#include <iostream>
#include <string>
#include <map>
#include <tuple>
#include <vector>
#include "Seat.h"
#include "Exceptions.h"
#include "ReservationStatus.h"
#include "CommonMethods.h"
using namespace std;
class Plane
{
private:
vector<map<char, Seat>> seats;
unsigned int numberOfRows, numberOfSeatsPerRow;
public:
Plane(unsigned int numberOfRows, unsigned int numberOfSeatsPerRow);
Plane() {}
void SetSeats(unsigned int numberOfRows, unsigned int numberOfSeatsPerRow);
};
void Plane::SetSeats(unsigned int numberOfRows, unsigned int numberOfSeatsPerRow)
{
//cout << "Clearing old seats" << endl;
if (!seats.empty())
{
//cout << "Seats not empty" << endl;
for (int i = 0; i < (int)seats.size(); i++)
{
//cout << "checking row " << i << endl;
if (!seats.at(i).empty())
{
//cout << "Row " << i << " not empty" << endl;
seats.at(i).clear();
}
}
}
cout << "Rows: " << numberOfRows << ", Seats: " << numberOfSeatsPerRow << endl;
this->numberOfRows = numberOfRows;
this->numberOfSeatsPerRow = numberOfSeatsPerRow;
for (unsigned int i = 0; i < this->numberOfRows; i++)
{
map<char, Seat> row;
for (unsigned int j = 0; j < this->numberOfSeatsPerRow; j++)
{
Seat seat;
seat.RowNumber = i + 1;
seat.SeatLetter = j + 'A';
//cout << "Inserting seat " << seat.RowNumber << seat.SeatLetter << endl;
row.insert(pair<char, Seat>(seat.SeatLetter, seat));
}
if (!row.empty())
{
cout << "inserting row " << (i + 1) << endl;
seats.push_back(row);
}
}
}
void Plane::ProcessWaitAny(int t)
{
while (!WaitingList.empty())
{
bool booked = false;
string pass = WaitingList.front();
WaitingList.pop();
for (unsigned int j = 0; j < numberOfRows; j++)
{
if (booked)
break;
for (unsigned int k = 0; k < numberOfSeatsPerRow; k++)
{
Seat *s = &seats.at(j)[k + 'A'];
if (!s->IsBooked)
{
Reserve(s, pass);
booked = true;
string seatNo = to_string(j);
seatNo += (k + 'A');
cout << "Passenger " << pass << " booked into seat " << seatNo << " at time " << t << endl;
break;
}
}
}
if (!booked)
return;
}
}
Code for Seat.h
#pragma once
#include <iostream>
#include <string>
#include <queue>
using namespace std;
struct Seat
{
string Passenger = "";
bool IsBooked = false;
unsigned int RowNumber;
char SeatLetter;
queue<string> WaitingList;
};
I have made a minimum working example of your problem:
#include <vector>
#include <sys/shm.h>
#include <iostream>
class Bar {
public:
Bar() {};
std::vector<int> vec;
};
int main() {
int shmid;
Bar* a = new Bar();
a->vec.push_back(1);
// set up shared memory segment
long key = 0x123455; // just a long integer
int nbytes = 1024;
shmid = shmget((key_t)key, nbytes, 0666 | IPC_CREAT);
if (shmid == -1)
{
printf("Error in shared memory region setup.\n");
perror("REASON");
exit(2);
}
a = (Bar*)shmat(shmid, (Bar*)0, 0);
a->vec.push_back(2);
}
The problem is your wrong usage of shmat. The pointer sharedPlane just points to some unitialized shared memory. You have to make sure that the address provided by key is 'right'. To do this, do the following:
Your other process, call Plane * other_process_sharedPlane = new Plane();. Remove the line sharedPlanes = new Plane[numPlanes]; from your main programm.
In your main process, set key to the value of other_process_sharedPlane
Then you can call shmget and shmadd

Why it gives me an extra words?

Write and test your own function char * funct (char * str, int x) inverting (except for the character at position n) the string str and returning the modified str as the result. The use of the function funct could be:
This is main:
#include <iostream>
#include <cstring>
using namespace std;
char* funct(char *str, int x);
int main() {
char str1 [] = "Hello cpp";
cout << str1 << endl; // Hello cpp
cout << funct (str, 1) << endl; // pepC ollH // the character at position 1 ('e') stays in place
return 0;
}
This is my function:
char* funct(char *str, int x) {
int counter = 0;
do {
counter++;
str++;
} while (*str);
str--;
char *wskTmp = str;
for (int i = 0; i < counter ; i++) {
*wskTmp = *str;
str--;
wskTmp++;
}
*wskTmp = '\0';
wskTmp = wskTmp - counter;
for (int i = 0; i < counter - x -1; i++) {
wskTmp++;
}
char tmp;
for (int i = 0; i < counter-3; i++) {
tmp = *(wskTmp - 1);
*(wskTmp - 1) = *wskTmp;
*wskTmp = tmp;
wskTmp--;
}
return str;
}
Output:
Hello Cpp
Hello CppepC ollH
It should be:
Hello Cpp
pepC ollH
Why it gives me Hello Cp before "pepC ollH"?
Your code is very confusing and is a very roundabout way of accomplishing this task, so I restructured it a bit:
#include <cstring>
#include <iostream>
using namespace std;
char *funct(char *str, int x) {
// keep track of the original start
char *origStr = str;
// iterate through the string to find the end
do {
str++;
} while (*str);
// decrease the string so it's on the last byte, not the nullbyte
str--;
// create a start and end
char *start = origStr;
char *end = str;
if (start - origStr == x) {
start ++;
}
if (end - origStr == x) {
end--;
}
// if start >= end then we've finished
while (start < end) {
// swap values at start and end
char temp = *start;
*start = *end;
*end = temp;
// move the pointers closer to each other
start++;
end--;
// skip the index x
if (start - origStr == x) {
start++;
}
// skip the index x
if (end - origStr == x) {
end--;
}
}
// make sure to return the actual start
return origStr;
}
int main() {
char str1[] = "Hello cpp";
cout << str1 << endl; // Hello cpp
cout << funct(str1, 1) << endl; // pepC ollH // the character at position 1
// ('e') stays in place
return 0;
}

How to insert an integer with leading zeros into a std::string?

In a C++14 program, I am given a string like
std::string s = "MyFile####.mp4";
and an integer 0 to a few hundred. (It'll never be a thousand or more, but four digits just in case.) I want to replace the "####" with the integer value, with leading zeros as needed to match the number of '#' characters. What is the slick C++11/14 way to modify s or produce a new string like that?
Normally I would use char* strings and snprintf(), strchr() to find the "#", but figure I should get with modern times and use std::string more often, but know only the simplest uses of it.
What is the slick C++11/14 way to modify s or produce a new string like that?
I don't know if it's slick enough but I propose the use of std::transform(), a lambda function and reverse iterators.
Something like
#include <string>
#include <iostream>
#include <algorithm>
int main ()
{
std::string str { "MyFile####.mp4" };
int num { 742 };
std::transform(str.rbegin(), str.rend(), str.rbegin(),
[&](auto ch)
{
if ( '#' == ch )
{
ch = "0123456789"[num % 10]; // or '0' + num % 10;
num /= 10;
}
return ch;
} // end of lambda function passed in as a parameter
); // end of std::transform()
std::cout << str << std::endl; // print MyFile0742.mp4
}
I would use regex since you're using C++14:
#include <iostream>
#include <regex>
#include <string>
#include <iterator>
int main()
{
std::string text = "Myfile####.mp4";
std::regex re("####");
int num = 252;
//convert int to string and add appropriate number of 0's
std::string nu = std::to_string(num);
while(nu.length() < 4) {
nu = "0" + nu;
}
//let regex_replace do it's work
std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
text.begin(), text.end(), re, nu);
std::cout << std::endl;
return 0;
}
WHy not use std::stringstream and than convert it to string.
std::string inputNumber (std::string s, int n) {
std::stringstream sstream;
bool numberIsSet = false;
for (int i = 0; i < s; ++i) {
if (s[i] == '#' && numberIsSet == true)
continue;
else if (s[i] == '#' && numberIsSet == false) {
sstream << setfill('0') << setw(5) << n;
numberIsSet = true;
} else
sstream << s[i];
}
return sstream.str();
}
I would probably use something like this
#include <iostream>
using namespace std;
int main()
{
int SomeNumber = 42;
std:string num = std::to_string(SomeNumber);
string padding = "";
while(padding.length()+num.length()<4){
padding += "0";
}
string result = "MyFile"+padding+num+".mp4";
cout << result << endl;
return 0;
}
Mine got out of control while I was playing with it, heh.
Pass it patterns on its command line, like:
./cpp-string-fill file########.jpg '####' test###this### and#this
#include <string>
#include <iostream>
#include <sstream>
std::string fill_pattern(std::string p, int num) {
size_t start_i, end_i;
for(
start_i = p.find_first_of('#'), end_i = start_i;
end_i < p.length() && p[end_i] == '#';
++end_i
) {
// Nothing special here.
}
if(end_i <= p.length()) {
std::ostringstream os;
os << num;
const std::string &ns = os.str();
size_t n_i = ns.length();
while(end_i > start_i && n_i > 0) {
end_i--;
n_i--;
p[end_i] = ns[n_i];
}
while(end_i > start_i) {
end_i--;
p[end_i] = '0';
}
}
return p;
}
int main(int argc, char *argv[]) {
if(argc<2) {
exit(1);
}
for(int i = 1; i < argc; i++) {
std::cout << fill_pattern(argv[i], 1283) << std::endl;
}
return 0;
}
I would probably do something like this:
using namespace std;
#include <iostream>
#include <string>
int main()
{
int SomeNumber = 42;
string num = std::to_string(SomeNumber);
string guide = "myfile####.mp3";
int start = static_cast<int>(guide.find_first_of("#"));
int end = static_cast<int>(guide.find_last_of("#"));
int used = 1;
int place = end;
char padding = '0';
while(place >= start){
if(used>num.length()){
guide.begin()[place]=padding;
}else{
guide.begin()[place]=num[num.length()-used];
}
place--;
used++;
}
cout << guide << endl;
return 0;
}

parsing input through char array to char pointer

So, the goal here is to set up a linux shell so that a user-input is processed in to how many arguments and the arguments themselves - ultimately to fork and execvp. I am having issues getting my commands to seperate. I need to count them, which is working fine, and separate the commands in to a char pointer array that they may be called. I had one method going where it would work if you had just one command, but if you did two it flipped out. I trashed it and went back to this method as I felt I was closer.. Anyhow.. This is standard operating system --homework--. I'm not looking for an answer, just some guidance or example to work from. Ultimately, if this method I'm currently using will not operate through execvp I'd appreciate just knowing that up front, too..
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
using namespace std;
int count_args(char *str);
void get_args(char* in_args, char** out_args);
int main() {
string my_path;
char user_input[1064];
char *args[64];
my_path = getenv("PATH");
while (1) {
cout << ">> ";
cin.getline(user_input, 1064);
int num_words = count_args(user_input);
get_args(user_input, args);
for (int i = 0; i < num_words; ++i) {
cout << num_words << " " << args[i] << endl;
}
}
return 0;
}
int count_args(char *str) {
int cnt = 0, space;
while (*str) {
if (*str == ' ' || *str == '\n' || *str == '\t') {
space = 0;
} else if (space == 0) {
space = 1;
++cnt;
}
++str;
}
return cnt;
}
void get_args(char* in_args, char** out_args) {
char str[64];
int pos = 0;
for (int i = 0; i < 64; ++i) {
str[i] = '0';
}
while (*in_args) {
if (*in_args != ' ' || *in_args != '\n' || *in_args != '\t') {
str[pos] = *in_args;
++pos;
} else {
memcpy(out_args, str, pos);
pos = 0;
}
*in_args = *in_args + 1;
}
}

Question on reversing a string

I get the following output: olleh�hello but can't figure out where I'm going wrong!
int main()
{
char hello[6] = "hello";
char temp[6];
unsigned int t = 0;
for(int i=strlen(hello)-1;i>=0;i--)
{
if(t<strlen(hello))
{
temp[t] = hello[i];
t++;
}
}
cout << temp;
return 0;
}
You need a null terminator at the end of the string:
int main()
{
char hello[6] = "hello";
char temp[6];
unsigned int t = 0;
for(int i=strlen(hello)-1;i>=0;i--)
{
if(t<strlen(hello))
{
temp[t] = hello[i];
t++;
}
}
temp[t] = '\0';
cout << temp;
return 0;
}
you tagged the question as [C++], so here's C++ way to reverse string:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string hello = "hello";
std::reverse(hello.begin(), hello.end());
std::cout << hello << std::endl;
}
it's difficult to make any mistake here
You aren't terminating temp with a null (\0), so temp isn't a valid string and cout doesn't know quite what to do with it. Your problem will go away if you add:
temp[5] = 0;
after the for loop.