How do I read a stringstream into a char *[40] / char ** array? - c++

I am working on creating a UNIX shell for a lab assignment. Part of this involves storing a history of the past 10 commands, including the arguments passed. I'm storing each command as a C++ string, but the parts of the program that actually matter, and that I had no input in designing (such as execve) use char * and char ** arrays exclusively.
I can get the whole command from history, and then read the program to be invoked quite easily, but I'm having a hard time reading into an arguments array, which is a char *[40] array.
Below is the code for a program I wrote to simulate this behavior on a test string:
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
char *chars[40];
string test = "Hi how are you";
stringstream testStream;
testStream << test;
int i = 0;
while (true)
{
string test_2;
testStream >> test_2;
if (testStream.fail())
{
break;
};
chars[i] = (char *)test_2.c_str();
i++;
}
for (int i=0; i < 4; i++)
{
cout << chars[i];
}
cout << "\n";
}
I get the feeling it has something to do with the array being declared as an array of pointers, rather than a multi-dimensional array. Am I correct?

This line:
chars[i] = (char *)test_2.c_str();
leaves chars[i] 'dangling' when you go back round the loop or fall off the end. This is because test_2.c_str() is only valid while test_2 is in scope.
You'd do better to do something like this:
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
int main()
{
std::vector <std::string> args;
std::string test = "Hi how are you";
std::stringstream testStream;
testStream << test;
int i = 0;
while (true)
{
std::string test_2;
testStream >> test_2;
if (testStream.fail())
break;
args.push_back (test_2);
i++;
}
auto char_args = std::make_unique <const char * []> (i);
for (int j = 0; j < i; ++j)
char_args [j] = args [j].c_str ();
for (int j = 0; j < i; ++j)
std::cout << char_args [j] << "\n";
}
Now your vector of strings remains in scope while you are building and using char_args.
Live demo

Related

std::cin string to int array with variable length input

I have a task where i need to revert a list of variable length numbers. This could be "1 2 3" or "5 6 7 8 9 10".
The sorting itself works fine.
But I can't figure out how to read the user input (with variable length) and then only execute the reverseSort once.
How can I read the user input into an array where each index is based on the space between the numbers?
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool sorted = true;
int temp;
int * arr;
int arrLength = 5;
int arrs;
// int arr = {1,2,3,4,5};
void reverseSort(int arr[], int n){
sorted = true;
for (int i = 0; i < n-1; i++){
if (arr[(i + 1)] > arr[i]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
sorted = false;
}
}
if (!sorted){
reverseSort(arr,n);
}
}
int main(void){
// get user input !?!?!?!?!
cin >> arrs;
cout << arrs;
reverseSort(arr,arrLength);
for (int i = 0; i < arrLength; i++){
std::cout << arr[i] << " ";
}
return 0;
}
If you don't know number of inputs you need struct that can be resized. std::vector is good for it. For adding new data you can use member function push_back.
You can read the input line as std::string (by std::getline) and you can open new stream with read data (std::istringstream). Further one can read values from new stream.
And I think you can use std::sort instead of reverseSort (but for 'reverse' you need use std::greater as comparator).
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
int main(void){
std::vector<int> arrs;
// read only one line
std::string input;
std::getline(std::cin, input);
std::istringstream row(input);
int x;
while (row >> x)
{
arrs.push_back(x);
}
//like your reverseSort
std::sort(arrs.begin(), arrs.end(), std::greater<int>{});
for (auto var : arrs) {
std::cout << var << "; ";
}
return 0;
}

C++ string array about nums

Say the strings is "Asah1234&^%736hsi)(91",
than storage 1234,736,91 in three arrays
In general,i want to put each continuous nums in each array.
Queations: how many arrays i will need,what's the size of each group of numbers,how to make the loop.
I want to write a fuction to do it.
#include<iostream>
using namespace std;
void splitString(string str)
{
string num;
for (int i = 0; i < str.length(); i++)
{
if (isdigit(str[i]))
num.push_back(str[i]);
}
cout << num << endl;
}
int countnum( string str)
{
string num;
int sum = 0;
for (int i = 0; i < str.length(); i++)
{
if (isdigit(str[i]))
sum++;
}
cout << sum << endl;
return 0;
}
int main()
{
const int MAXLEN = 100;
char str[MAXLEN];
printf("please enter strings:");
scanf_s("%s", str, MAXLEN);
splitString(str);
countnum( str);
return 0;
}
Maybe I have a misunderstanding here. Then please comment and I will delete the answer.
This is a standard task and will be solved with a regex. It is just the definition of a variable and initialzing this variable with its range constructor. So, a one-liner.
There is no further statement needed.
Please see:
#include <iostream>
#include <string>
#include <regex>
#include <vector>
std::regex re{ R"(\d+)" };
int main() {
// The input string with test data
std::string test{"Asah123&^%736hsi)(918"};
// Define a variable numbers and use the range constructor to put all data in it
std::vector numbers(std::sregex_token_iterator(test.begin(), test.end(), re), {});
// Show the result on the screen
for (const auto& n : numbers) std::cout << n << "\n";
return 0;
}

Displaying all prefixes of a word in C++

I am trying to do is display all the suffixes of a word as such:
word: house
print:
h
ho
hou
hous
house
What I did is:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for(k=0;k<i;k++)
{
if(k==0)
{
cout<<cuvant[k]<<endl;
}else
{
for(k=1;k<=i;k++){
if(k==i) cout<<endl;
cout<<cuvant[k];
}
}
}
}
}
What am I doing wrong?
You're over-complicating it. Here's a simpler way:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s;
std::cin >> s;
for (std::string::size_type i = 0, size = s.size(); i != size; ++i)
std::cout << std::string_view{s.c_str(), i + 1} << '\n';
}
If you don't have access to a C++17 compiler, you can use this one:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
int main() {
std::string s;
std::cin >> s;
for (auto const& ch : s) {
std::copy(s.c_str(), (&ch + 1),
std::ostream_iterator<decltype(ch)>(std::cout));
std::cout << '\n';
}
}
Even so, I think it would be better for your learning progress to use a debugger to finger out the problem yourself. Here the problems with your code:
For the i=0 (the first iteration of your outer loop) the for(k=0;k<i;k++) will not be executed at all, as k<0 evaluates to false.
And having a running variable (k) that you change in two for loops that are nested, is most of the time also an indication that something is wrong.
So what you want to do: You want to create each possible prefix, so you want to create n strings with the length of 1 to n. So your first idea with the outer loop is correct. But you overcomplicate the inner part.
For the inner part, you want to print all chars from the index 0 up to i.
int main() {
char cuvant[100];
std::cin >> cuvant;
// loop over the length of the string
for (int i = 0, size = strlen(cuvant); i < size; i++) {
// print all chars from 0 upto to i (k<=0)
for (int k = 0; k <= i; k++) {
std::cout << cuvant[k];
}
// print a new line after that
std::cout << std::endl;
}
}
But instead of reinventing the wheel I would use the functions the std provides:
int main() {
std::string s;
std::cin >> s;
for (std::size_t i = 0, size = s.size(); i < size; i++) {
std::cout << s.substr(0, i + 1) << std::endl;
}
}
For this very simple string suffix task you can just use:
void main()
{
std::string s = "house";
std::string s2;
for(char c : s)
{
s2 += c;
cout << s2 << endl;
}
}
For more complicated problems you may be interested to read about Suffix Tree
Your code is wrong, the following code can fulfill your requirements
#include <iostream>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for (k = 0; k <= i; ++k)
{
cout<<cuvant[k];
}
cout<<endl;
}
}

How to read in an array of chars as ints with spaces included?

I'm trying to create a program that reads in and solves incomplete 9x9 sudoku boards from a text file. One of the boards might look like this:
N
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
I need to print out the board read in, which I'm doing by just using getline and printing the string, and then store each digit into an array, blanks can be converted to zeroes for the purpose of evaluation. If I tried to read the board in as straight ints then it would try to read all the digits of a row as one int until a space or a newline was reached, and if I try to read it in char by char with get(), I run into problems again with newlines, and I would then have to convert the array of chars to an array of ints for evaluation which I think I will run into problems with as well. This is my code so far, I figured using an istringstream would be convenient but then realized that I would have to have more for loops, so a solution without it would be ideal. Not allowed to use vectors or fancy modules or structs anything like that, it is a class assignment.
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
using namespace std;
int main() {
ifstream infile("sudoku_infile.txt");
ofstream outfile("sudoku_outfile.txt");
int board[9][9];
char n;
char c;
string str;
stringstream into;
while (infile >> n){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
into << str;
}
return 0;
}
EDIT:
Ok, I've devised a solution on my own by trying to convert chars to ints and putting them in an array, but it doesn't seem to be working:
while (infile >> str){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
for (int z = 0; z < 9; z++){
if (isdigit(str[z])){
d = str[z] - '0';
}
else{
d = 0;
}
board[i][j] = d;
}
}
for (int m = 0; m < 9; m++){
for (int f = 0; f < 9; f++)
cout << board[m][f];
cout << endl;
}
}
I get this as output:
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
071924836
555555555
555555555
555555555
555555555
555555555
555555555
555555555
555555555
You have to make sure, that your file just contains up to 9*9 characters - otherwise it will run out of bounds this way - but it's easy to add a bounds check in there. Because '0' starts in ASCII at index 48, I'm calculating the char value minus the magic number 48.
However you still have to add a check for ' ' by yourself (otherwise it gets initalized with -16), but I'm sure you can do it!
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
int main(int argc, char **argv) {
std::ifstream infile("sudoku_infile.txt");
std::ofstream outfile("sudoku_outfile.txt");
int board[9][9];
size_t index = 0;
std::string str;
while (std::getline(infile, str)){
//std::cout << str << "\n";
for (size_t i = 0; i < str.size(); i++, index++){
board[index%9][index/9] = str[i] - '0';
}
}
return 0;
}
This can easily be done with one of the standard algorithm functions, namely std::copy. You can use it with iterator helpers like std::istream_inserter and std::back_inserter.
Use the above functions to put the integers into a std::vector.
After you're done with the basics, learning to use the standard library will really help you.
For example, even though you can't use it for this assignment, the above mentioned functions could be used like this:
std::vector<std::string> vs;
std::copy(std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>(),
std::back_inserter(vs));
After the above, the vector vs will contain all white-space delimited string from the infile stream.
To then get it into a board, you could to like this:
std::array<std::array<int, 9>, 9> board;
int i = 0;
for (const std::string& s : vs)
{
int j = 0;
for (const char& c : s)
board[i][j++] = c - '0';
++i;
}

Traverse file vertically

I need to traverse a file in a vertical manner. If suppose the file contents are:
adg
beh
cfi
It should print the file as:
abc
def
ghi
The length for each line will be same(i.e. all lines will be of length 3 for above example). I have written a code but it doesn't traverse the file as required.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
fstream fs;
fs.open("asd.txt",ios::in);
string str;
char *ch = new char();
int lineLen = 0, k = 0;
if(getline(fs,str))
{
lineLen = str.length();
}
fs.seekg(0);
if(lineLen > 0)
{
for(int i = 0;i<lineLen;i++)
{
fs.seekg(i+k*lineLen);
while(fs.read(ch,1))
{
k++;
fs.seekg(i+k*lineLen);
cout<<*ch;
}
k = 0;
}
}
fs.close();
cin.ignore();
}
I am a bit new to file handling and couldn't find the mistake. Also, is there a better approach for this to be followed?
Pretty much your way with some little tweaks
//lines = no. of lines in file
fs.seekg(0, fs.beg);
fs.clear();
if(lineLen > 0)
{
for(int k = 0; k < lineLen; k++) {
for(int i = 0;i<lines;i++){
fs.seekg(k+i * (lineLen + 2), fs.beg); //use lines + 2
if(fs.read (ch,1));
cout << *ch;
}
cout << endl;
}
Untested pseudo-code that may give you some ideas. Basically, load the whole file into a 2d vector of characters for easy access. It will use more memory than reading directly from the file but this won't matter unless the file is very big.
vector<vector<char>> filemap;
string line;
while (getline(filestream, line))
{
filemap.push_back(vector<char>(line.begin(), line.end()));
}
for (int x = 0; x < XSIZE; x++)
{
for (int y = 0; y < YSIZE; y++)
{
filestream << filemap[y][x]; // note x/y are opposite way round in 2d vectors
}
filestream << '\n';
}
You might find this task much simpler if you were to use mmap(2). There may be a C++ equivalent or wrapper, but I'm afraid I'm not much of an expert on that front. Hopefully someone will come along with a better answer if that's the case.
Here's a quick C (not ++) example. I'll see if I can google around and C++ify it some more:
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
int fd = open("input", O_RDONLY);
struct stat s;
fstat(fd, &s);
// map the file as one big string
char *c = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
// calculate sizes
int columns = strchr(c, '\n') - c; // first newline delimits a row
int stride = columns + 1; // count the newline!
int rows = s.st_size / stride; // all rows are the same length
for (int x = 0; x < columns; x++)
{
for (int y = 0; y < rows; y++)
{
putchar(c[y*stride + x]);
}
putchar('\n');
}
munmap(c, s.st_size);
close(fd);
return 0;
}
Edit: A quick search around didn't turn up a much better way to handle this in C++ as far as I could tell. I mean, I can add a typecast on the mmap line and change the putchar calls to std::cout, but that doesn't really seem like it makes any difference.
Instead of trying to seek() repeatedly in the source file it is much easier and faster to simply read in the whole source file then generate output from the in-memory contents.
This sounds an awful like like a class assignment, so I won't simply write the answer for you. However this should point you in the right way -- Some PseodoCode is included
To avoid pain, it should presumably be safe to assume some upper bound on line length and max lines, i.e.,
const int MaxLines = 100;
const int MaxLength = 80;
int lineno, linelength;
// array of char pointers for each line
char *lines[] = (*lines[])malloc(Maxlines * sizeof(char*));
// ReadLoop
lineno = 0;
while (not eof)
{
getline(buffer);
if (++lineno++ == 1)
{
linelength = strlen(buffer);
}
else
{
if (linelength != strlen(buffer))
{
cout "Line # " << lineno << " does not match the expected length";
exit();
}
}
lines[lineno] = malloc(strlen(buffer)+1));
strcpy(lines[lineno], buffer);
}
int cc, linecnt = lineno;
// now all data in memory, output "vertical data"
for (cc = 0; cc < linelength; ++cc)
{
for (lineno=0; lineno<<linelength; ++lineno)
{
cout << lines[xx][yy]; // xx && yy left you to figure out
}
cout "\n";
}
Provided that your file is not enormous, there's no reason not to just slurp the whole thing into memory. There may be a more idiomatic way to do this in C++, but the following works:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
int main(int argc, char *argv[])
{
std::fstream infile("foo.txt");
std::vector<std::string> lines;
std::string line;
while(std::getline(infile,line)) {
lines.push_back(line);
}
int m=lines.size();
int n=lines[0].length();
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
std::cout << lines[j].at(i);
}
std::cout << std::endl;
}
return 0;
}
Problems arise when all the lines in the file are not the same length, of course.
And now, a version that “doesn't use any extra memory” (of course, it does, but not much):
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
std::fstream infile("foo.txt");
std::vector<std::string> lines;
std::string line;
std::getline(infile, line);
int n = line.length();
int m = 1+std::count(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), '\n');
infile.clear();
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
infile.seekg(j*m+i);
std::cout << char(infile.peek());
}
std::cout << std::endl;
}
return 0;
}