parsing input through char array to char pointer - c++

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;
}
}

Related

Random and replacement characters in c++ output

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};

How to make sure that two strings only have certain alphabets in c++

Aim is to make sure that the user entered input for string 1 and string 2 contains only characters A,T,G or C in any order. If either string contains another other character then error should be displayed. Example:
Input contains error
Error in String #1: aacgttcOgMa
Error in String #2: ggataccaSat
This is my attempt at LCS.cpp file code:
#include "LCS.h"
#include <string>
using namespace std;
bool validate(string strX, string strY)
{
string x = strX;
string y = strY;
char searchItem = 'A';
char searchItem = 'C';
char searchItem = 'G';
char searchItem = 'T';
int numOfChar = 0;
int m = strX.length();
int n = strY.length();
for (int i = 0; i < m; i++)
{
if (x[i] == searchItem)
{
numOfChar++;
}
for (int i = 0; i < n; i++)
{
if (y[i] == searchItem)
{
numOfChar++;
}
}
}
This is my LCS.h file code:
#pragma once
#ifndef LCS_H
#define LCS_H
#include <string>
using namespace std;
bool validate(string strX, string strY);
#endif
And my driver file "Driver6.cpp" has this code:
#include "LCS.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string strX, strY;
cout << "String #1: ";
cin >> strX;
cout << "String #2: ";
cin >> strY;
//validate the input two strings
if (validate(strX, strY) == false)
{
return 0;
}
int m = strX.length();
int n = strY.length();
}
Didn't really want to do this but it seems like the best bet rather than going round the houses in the comments:
#include <string>
#include <iostream>
bool validate( const std::string & s ) {
for ( auto c : s ) {
if ( c != 'A' && c != 'T' && c != 'C' && c != 'G' ) {
return false;
}
}
return true;
}
int main() {
std::string s1 = "ATGCCCG";
std::string s2 = "ATGfooCCCG";
if ( validate( s1 ) ) {
std::cout << "s1 is valid\n";
}
else {
std::cout << "s1 is not valid\n";
}
if ( validate( s2 ) ) {
std::cout << "s2 is valid\n";
}
else {
std::cout << "s2 is not valid\n";
}
}
Another technique:
bool validate(const std::string& s)
{
const static std::string valid_letters("ATCGatcg");
for (auto c: s)
{
std::string::size_type position = valid_letters.find_first_of(c);
if (position == std::string::npos)
{
return false;
}
}
return true;
}
The above code searches a container of valid letters.

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;
}

Taking Each Individual Word From a String in C++

I am writing a method in C++ which will take a string of 2 or more words and output each individual word of the string separated by a second or so, using the sleep() method. I am trying to do this using a for loop and substrings. I am unsure also of the regexs which should be used, and how they should be used, to achieve the desired output.
I have reviewed this and this and find my question differs since I am trying to do this in a loop, and not store the individual substrings.
Input:
"This is an example"
Desired output:
"This " (pause) "is " (pause) "an " (pause) "example."
Use std::stringstream, no regular expressions required:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
stringstream ss("This is a test");
string s;
while (ss >> s) {
cout << s << endl;
}
return 0;
}
Also, see How do I tokenize a string in C++?
Here are a pair of implementations that don't involve creating any extraneous buffers.
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm/copy.hpp> //for boost::copy
#include <chrono>
#include <iostream>
#include <string>
#include <experimental/string_view> //in clang or gcc; or use boost::string_ref in boost 1.53 or later; or use boost::iterator_range<char*> in earlier version of boost
#include <thread>
void method_one(std::experimental::string_view sv)
{
for(auto b = sv.begin(), e = sv.end(), space = std::find(b, e, ' ')
; b < e
; b = space + 1, space = std::find(space + 1, e, ' '))
{
std::copy(b, space, std::ostreambuf_iterator<char>(std::cout));
std::cout << " (pause) "; //note that this will spit out an extra pause the last time through
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void method_two(std::experimental::string_view sv)
{
boost::copy(
sv | boost::adaptors::filtered([](const char c) -> bool
{
if(c == ' ')
{
std::cout << " (pause) "; //note that this spits out exactly one pause per space character
std::this_thread::sleep_for(std::chrono::seconds(1));
return false;
}
return true;
})
, std::ostreambuf_iterator<char>(std::cout)
);
}
int main() {
const std::string s{"This is a string"};
method_one(s);
std::cout << std::endl;
method_two(s);
std::cout << std::endl;
return 0;
}
Live on coliru, if you're into that.
you can implement your own method:
//StrParse.h
#pragma once
#include <iostream>
static counter = 0;
char* strPar(char* pTxt, char c)
{
int lenAll = strlen(pTxt);
bool strBeg = false;
int nWords = 0;
for(int i(0); i < lenAll; i++)
{
while(pTxt[i] != c)
{
strBeg = true;
i++;
}
if(strBeg)
{
nWords++;
strBeg = false;
}
}
int* pLens = new int[nWords];
int j = 0;
int len = 0;
for(i = 0; i < lenAll; i++)
{
while(pTxt[i] != c)
{
strBeg = true;
i++;
len++;
}
if(strBeg)
{
pLens[j] = len;
j++;
strBeg = false;
len = 0;
}
}
char** pStr = new char*[nWords + 1];
for(i = 0; i < nWords; i++)
pStr[i] = new char[pLens[i] + 1];
int k = 0, l = 0;
for(i = 0; i < lenAll; i++)
{
while(pTxt[i] != c)
{
strBeg = true;
pStr[k][l] = pTxt[i];
l++;
i++;
}
if(strBeg)
{
pStr[k][l] = '\0';
k++;
l = 0;
strBeg = false;
}
}
counter++;
if(counter <= nWords)
return pStr[counter - 1];
else
return NULL;
}
//main.cpp
#include "StrParse.h"
void main()
{
char* pTxt = " -CPlusPlus -programming -is -a - superb thing ";
char* pStr1 = NULL;
int i = 1;
char sep;
std::cout << "Separator: ";
sep = std::cin.get();
std::cin.sync();
while(pStr1 = strPar(pTxt, sep))
{
std::cout << "String " << i << ": " << pStr1 << std::endl;
delete pStr1;
i++;
}
std::cout << std::endl;
}

How to split char pointer with multiple delimiters & return array of char pointers in c++?

In the duplicate of this question Split char* to char * Array it is advised to use string rather than char*. But I need to work with LPWSTR. Since it's a typedef of char*, I prefer to use char*. I tried with the following code, which gives the wrong output:
char**splitByMultipleDelimiters(char*ori,char deli[],int lengthOfDelimiterArray)
{
char*copy = ori;
char** strArray = new char*[10];
int j = 0;
int offset = 0;
char*word = (char*)malloc(50);
int length;
int split = 0;
for(int i = 0; i < (int)strlen(ori); i++)
{
for(int k = 0; (k < lengthOfDelimiterArray) && (split == 0);k++)
{
if(ori[i] == deli[k])
{
split = 1;
}
}
if(split == 1)//ori[i] == deli[0]
{
length = i - offset;
strncpy(word,copy,length);
word[length] = '\0';
strArray[j] = word;
copy = ori + i + 1;
//cout << "copy: " << copy << endl;
//cout << strArray[j] << endl;
j++;
offset = i + 1;
split = 0;
}
}
strArray[j] = copy;
// string strArrayToReturn[j+1];
for(int i = 0; i < j+1; i++)
{
//strArrayToReturn[i] = strArray[i];
cout << strArray[i] << endl;
}
return strArray;
}
void main()
{
char*ori = "This:is\nmy:tst?why I hate";
char deli[] = {':','?',' ','\n'};
int lengthOfDelimiterArray = (sizeof(deli)/sizeof(*deli));
splitByMultipleDelimiters(ori,deli,lengthOfDelimiterArray);
}
Are there any other ways to split LPWSTR?
Wait, what are you talking about? I don't see LPWSTR anywhere in your code. Are you trying to convert to LPWSTR? If so, there's a standard library function for that. There's also a standard library-based solution for splitting over multiple chars. So all together, your code might look like this:
#include <codecvt>
#include <cstdio>
#include <locale>
#include <sstream>
#include <string>
using std::string;
using std::wstring;
wstring toWide(const string &original)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(narrow_utf8_source_string);
}
std::vector<wstring> splitMany(const string &original, const string &delimiters)
{
std::stringstream stream(original);
std::string line;
while (std::getline(original, line))
{
std::size_t prev = 0, pos;
while ((pos = line.find_first_of(delimeters, prev)) != std::string::npos)
{
if (pos > prev)
wordVector.push_back(line.substr(prev, pos-prev));
prev = pos + 1;
}
if (prev < line.length())
wordVector.push_back(line.substr(prev, std::string::npos));
}
}
int main()
{
string original = "This:is\nmy:tst?why I hate";
string separators = ":? \n"
std::vector<wstring> results = splitMany(original, separators);
}
This code uses the standard library for these functions and is much less error-prone than doing it manually.
Good luck!
Edit: To be clear, wstring == LPWSTR == wchar_t*.
Edit 2: To convert a string to a wstring:
#include <codecvt>
#include <locale>
#include <string>
using std::string;
using std::wstring;
string toMultiByte(const wstring &original)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.to_bytes(original);
}