I'm getting funky output when running this code. There isn't a compile error. As far as I can tell, the problem is in my getArgs(stringstream& ss, int size) function. The strings are not copying correctly into my char* variables. I wanted a dynamic array of char* to save my command line arguments to. What am I doing wrong here?
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct arguments
{
int argc; //number of arguments
char **argv; //array of arguments
};
void startupMsg()
{
cout << "******** CS415 SHELL ********" << endl;
}
int countArgs(stringstream& ss)
{
string temp;
int count = 0;
while (ss >> temp)
{
count++;
}
return count;
}
char** getArgs(stringstream& ss, int size)
{
ss.clear();
ss.seekg(0, ios::beg);
char **ary = new char*[size];
for (int i = 0; i < size; i++)
ary[i] = new char;
int c = 0;
string temp;
while (ss >> temp)
{
ary[c] = const_cast<char*>(temp.c_str());
c++;
}
return ary;
}
void printArgs(arguments* args)
{
for (int i = 0; i < args->argc; i++)
{
cout << args->argv[i] << " ";
}
cout << endl;
}
arguments* parseCommand(string command)
{
arguments *args = new arguments;
stringstream ss(command);
args->argc = countArgs(ss);
args->argv = getArgs(ss, args->argc);
return args;
}
int main()
{
string command;
startupMsg();
//while(true)
//{
cout << "user#linux:~$ ";
getline(cin, command);
arguments *args = parseCommand(command);
cout << args->argc << endl;
printArgs(args);
//}
}
Your problem is here:
ary[c] = const_cast<char*>(temp.c_str());
A good rule of thumb is when you find yourself needing const_cast, you're probably doing something wrong. It's not like you never need it, but it's quite an exceptional thing.
In any case, what happens here? Okay, you read into ary[0] a pointer into temp's buffer. Now you get your next argument. Best case, ary[0] and ary[1] now point to the same argument and you've lost the first one. Worst case, temp had to reallocate and now ary[0] is already a dangling pointer.
Regardless, at the end of getArgs(), temp is destroyed, and now all your likely-not-even-different pointers are dangling.
That's bad. You'll need to come up with some different.
Related
I am writing a C++ program for homework, and it needs to count the characters in a char arr[n] string. However, my counter keeps returning the wrong values. I have looked through other answers to similar questions, however, they are not specific to C++ and none of the answers explain the value I am getting.
#include<iostream>
using namespace std;
#include<string.h>
#include <stdlib.h>
class Counter
{
public:
char word[20];
int totChar{ 0 };
void setWord(char word)
{
this->word[20] = word;
}
void setCount(int totChar)
{
this->totChar = totChar;
}
int getLength()
{
return totChar;
}
void charCount()
{
int n = 0;
for (int i = 0; word[i] != '\0'; i++) {
if (word[i] != '\0')
{
n++;
}
}
setCount(n);
}
};
int main()
{
char text[20];
cout << "Enter the string:" << endl;
cin >> text;
Logic input;
input.setWord(text[20]);
input.charCount();
// input.resetWord();
cout << input.getLength();
}
So it seems you haven't figured out how arrays and C strings work in C++ yet.
void setWord(const char* word)
{
strcpy(this->word, word);
}
and
Logic input;
input.setWord(text);
Your code is a bit weird, I guess you are just experimenting, but I think those two changes should make it work.
I want to write a function that receive an int argument then converter to a char pointer (c-string), but my code output is not right.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
char *stoc(int n){
stringstream stream;
stream <<"Log"<<n<<".txt";
string name;
stream >>name;
int len = name.length();
char ch[len+1];
for(int i=0; i<len; i++){
ch[i]=name[i];
}
ch[len+1] = '\0';
return ch;
}
int main() {
char *name = stoc(3);
cout << name << endl;
return 0;
}
Summarising the comments:
You normally do not use C-style-strings in C++, just stick to std::strings. Therefor you should rather return name instead of your converted ch, especially since you have already created a std::string. Having access to at least C++11 you can then easily convert your rather long function into a one-liner
C++11
std::string stoc(int n) {
return "Log" + std::to_string(n) + ".txt";
}
prior C++11
std::string stoc(int n) {
std::ostringstream oss;
oss << "Log" + n + ".txt";
return oss.str(); // by accessing a stringstreams content directly there is no need to use an extra variable
}
If you do need to use a C-style-string later on somewhere, e.g. as a parameter for a C-library function, you can use c_str to convert any std::string into it's C-style equivalent:
int main() {
std::string name = stoc(3);
std::cout << name << std::endl;
}
You should do this instead of returning a pointer to a local variable (which yields in undefined behaviour):
...
char *ch = new char[len+1];
for(int i=0; i<len; i++){
ch[i]=name[i];
}
ch[len] = '\0';
...
int main() {
char *name = stoc(3);
cout << name << endl;
delete [] name; // delete what has been allocated in stoc
return 0;
}
Also note the ch[len] = '\0' instead of ch[len + 1] = '\0'.
But in C++ you should rather use std::string and not deal with char arrays, new and delete at all.
Ok so this code does compile, and it does run, but it does NOT give me the correct output for EITHER the original or reverse array, just gibberish. I spent the last 4 hours trying to see where I went wrong (it wasn't working at all before and now that I got it to at least output what SHOULD be a C-string, i get gibberish). Someone please help me see where I went wrong.
#include <iostream>
#include <cstring>
using namespace std;
char* getInput();
char* getReverse(char[], int);
void displayResults(char *, char *);
const int MAX_SIZE = 21;
int main()
{
//program to create a c-string and then output the reverse order
char *original;
char *reverse;
original = getInput();
int originalSize = strlen(original);
reverse = getReverse(original, originalSize);
displayResults(original, reverse);
return 0;
}
/***************************************************
Definition of function- getInput: *
prompts the user to enter in a line of text to a *
max amount of characters. Returns a pointer to the *
C-string array. *
****************************************************/
char* getInput()
{
char *originalptr;
char original[MAX_SIZE];
cout << "Enter a word or line of text up to a max of 20 characters\nand will have it output in reverse!" << endl;
cin.getline(original, MAX_SIZE);
originalptr = original;
return originalptr;
}
char* getReverse(char *reverseThis, int size)
{
char* reverseOutput;
char reverse[MAX_SIZE];
int counter = 0;
while(*reverseThis != '\0')
{
reverse[counter] = *(reverseThis + (size - counter));
reverseThis++;
counter++;
}
reverseOutput = reverse;
return reverseOutput;
}
void displayResults(char *original, char *reverse)
{
cout << "\nYou originally entered: " << original << endl;
cout << "In reverse order: " << reverse << endl;
}
In 'getReverse' you are allocating the variable 'reverse' on the STACK meaning the data will be GONE WHEN THE FUNCTION RETURNS, no matter how many pointers reference that data.
I would declare 'reverse' in main with 'char reverse[MAX_SIZE];', then have the function take a parameter 'char reverse[]', which the function would then modify.
You are returning a pointer to a local array. The array original is destroyed after the function getInput exits. So original in main is pointing at something which no longer exists, garbage in other words. getReverse has exactly the same problem.
One way to solve this is to declare the arrays in main, and pass pointers to those arrays to the getInput and getReverse functions, for instance.
int main()
{
//program to create a c-string and then output the reverse order
char original[MAX_SIZE];
char reverse[MAX_SIZE];
getInput(original);
int originalSize = strlen(original);
getReverse(original, originalSize, reverse);
displayResults(original, reverse);
return 0;
}
void getInput(char* original)
{
cout << "Enter a word or line of text up to a max of 20 characters\nand will have it output in reverse!" << endl;
cin.getline(original, MAX_SIZE);
}
// etc
You are wasting too much char* s and data. Why not try this :
(I have not tested the code, but it must work ,probably with minor fixes,if any.)
#define MAXSIZE 20
void getinput(char *in)
{
cin.getline(in,MAXSIZE);
return;
}
void reverse(char *in);
{
int len=strlen(in);
char *store=in;
while(int i=0;i<len/2;i++)
{
char temp;
temp=*in;
*in=*(store+len);
in++;len--;
}
return;
}
int main()
{
char data[MAXSIZE];
getinput(data);
cout<<"Original :"<<data;
reverse(data);
cout<<"reverse"<<data;
}
I am trying to get user input and put it into an array of cstrings separated by a space. When I print the array to the screen though I get nothing. I am sure I am doing something stupid, but I have been stuck trying different ways for a while. Any help would be appreciated. Here is the code.
#include <iostream>
#include <cstring>
using namespace std;
void stuff(char command[][25], int length)
{
char ch;
for(int i = 0; i < length; i ++)
{
int b = 0;
cin.get(ch);
while(!isspace(ch))
{
command[i][b++] = ch;
cin.get(ch);
}
command[i][b] = '\0';
cout << endl;
}
}
int main()
{
char cha[10][25];
char ch;
int len = 0;
while(ch != '\n')
{
cin.get(ch);
if(isspace(ch))
{
len++;
}
}
stuff(cha,len);
for(int i = 0; i < len; i++)
{
cout << cha[i] << endl;
}
cout << len << endl;
return 0;
}
a) ch is undefined when you first test it with while (ch != '\n'). Initialize it to zero or something.
b) You don't write any values into cha in the while loop. Perhaps something like:
int pos = 0;
while(ch != '\n') {
cin.get(ch);
if (isspace((unsigned)ch)) {
if (pos > 0) {
++len;
pos = 0;
}
}
else {
cha[len][pos] = ch;
++pos;
}
}
c) You are reading the stream again in stuff(...) but have already consumed what you wanted to get from the stream in main().
d) This code suffers from a number of buffer overrun and stack corruption opportunities. perhaps use a std::vector<std::string> instead. If it runs out of memory it will throw an exception rather than make a mess on the stack.
Perhaps something like this (untested):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void main()
{
typedef std::vector<std::string> strvec;
strvec cha;
std::string s;
char ch = 0;
while(ch != '\n') {
cin.get(ch);
if (isspace((unsigned)ch)) {
if (!s.empty()) {
cha.push_back(s);
s.clear();
}
}
else {
s.push_back(ch);
}
}
// don't need to call 'stuff' to null terminate.
for (strvec::iterator i = cha.begin(); i != cha.end(); ++i) {
cout << *i << endl;
}
cout << cha.size() << endl;
}
This could be a little more efficient than it is but hopefully it is easy to understand.
You are reading the whole input in the while cycle in the main to read length(number of strings), but you never store it. Later on in stuff cin.get will read nothing. Maybe store the input in cha during the first cycle?
Can someone help me with this: This is a program to find all the permutations of a string of any length. Need a non-recursive form of the same. ( a C language implementation is preferred)
using namespace std;
string swtch(string topermute, int x, int y)
{
string newstring = topermute;
newstring[x] = newstring[y];
newstring[y] = topermute[x]; //avoids temp variable
return newstring;
}
void permute(string topermute, int place)
{
if(place == topermute.length() - 1)
{
cout<<topermute<<endl;
}
for(int nextchar = place; nextchar < topermute.length(); nextchar++)
{
permute(swtch(topermute, place, nextchar),place+1);
}
}
int main(int argc, char* argv[])
{
if(argc!=2)
{
cout<<"Proper input is 'permute string'";
return 1;
}
permute(argv[1], 0);
return 0;
}
Another approach would be to allocate an array of n! char arrays and fill them in the same way that you would by hand.
If the string is "abcd", put all of the "a" chars in position 0 for the first n-1! arrays, in position 1 for the next n-1! arrays, etc. Then put all of the "b" chars in position 1 for the first n-2! arrays, etc, all of the "c" chars in position 2 for the first n-3! arrays, etc, and all of the "d" chars in position 3 for the first n-4! arrays, etc, using modulo n arithmetic in each case to move from position 3 to position 0 as you are filling out the arrays.
No swapping is necessary and you know early on if you have enough memory to store the results or not.
A stack based non-recursive equivalent of your code:
#include <iostream>
#include <string>
struct State
{
State (std::string topermute_, int place_, int nextchar_, State* next_ = 0)
: topermute (topermute_)
, place (place_)
, nextchar (nextchar_)
, next (next_)
{
}
std::string topermute;
int place;
int nextchar;
State* next;
};
std::string swtch (std::string topermute, int x, int y)
{
std::string newstring = topermute;
newstring[x] = newstring[y];
newstring[y] = topermute[x]; //avoids temp variable
return newstring;
}
void permute (std::string topermute, int place = 0)
{
// Linked list stack.
State* top = new State (topermute, place, place);
while (top != 0)
{
State* pop = top;
top = pop->next;
if (pop->place == pop->topermute.length () - 1)
{
std::cout << pop->topermute << std::endl;
}
for (int i = pop->place; i < pop->topermute.length (); ++i)
{
top = new State (swtch (pop->topermute, pop->place, i), pop->place + 1, i, top);
}
delete pop;
}
}
int main (int argc, char* argv[])
{
if (argc!=2)
{
std::cout<<"Proper input is 'permute string'";
return 1;
}
else
{
permute (argv[1]);
}
return 0;
}
I've tried to make it C-like and avoided c++ STL containers and member functions (used a constructor for simplicity though).
Note, the permutations are generated in reverse order to the original.
I should add that using a stack in this way is just simulating recursion.
First one advice - don't pass std:string arguments by value. Use const references
string swtch(const string& topermute, int x, int y)
void permute(const string & topermute, int place)
It will save you a lot of unnecessary copying.
As for C++ solution, you have functions std::next_permutation and std::prev_permutation in algorithm header. So you can write:
int main(int argc, char* argv[])
{
if(argc!=2)
{
cout<<"Proper input is 'permute string'" << endl;
return 1;
}
std::string copy = argv[1];
// program argument and lexically greater permutations
do
{
std::cout << copy << endl;
}
while (std::next_permutation(copy.begin(), copy.end());
// lexically smaller permutations of argument
std::string copy = argv[1];
while (std::prev_permutation(copy.begin(), copy.end())
{
std::cout << copy << endl;
}
return 0;
}
As for C solution, you have to change variables types from std::string to char * (ugh, and you have to manage memory properly). I think similar approach - writing functions
int next_permutation(char * begin, char * end);
int prev_permutation(char * begin, char * end);
with same semantics as STL functions - will do. You can find source code for std::next_permutation with explanation here. I hope you can manage to write a similar code that works on char * (BTW std::next_permutation can work with char * with no problems, but you wanted C solution) as I am to lazy to do it by myself :-)
Have you tried using the STL? There is an algorithm called next_permutation which given a range will return true on each subsequent call until all permutations have been encountered. Works not only on strings but on any "sequence" type.
http://www.sgi.com/tech/stl/next_permutation.html
This solves the problem without recursion. The only issue is that it will generate duplicate output in the case where a character is repeated in the string.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
#include<string.h>
int factorial(int n)
{
int fact=1;
for(int i=2;i<=n;i++)
fact*=i;
return fact;
}
char *str;
void swap(int i,int j)
{
char temp=str[i];
str[i]=str[j];
str[j]=temp;
}
void main()
{
clrscr();
int len,fact,count=1;
cout<<"Enter the string:";
gets(str);
len=strlen(str);
fact=factorial(len);
for(int i=0;i<fact;i++)
{
int j=i%(len-1);
swap(j,j+1);
cout<<"\n"<<count++<<". ";
for(int k=0;k<len;k++)
cout<<str[k];
}
getch();
}
#include <iostream>
#include <string>
using namespace std;
void permuteString(string& str, int i)
{
for (int j = 0; j < i; j++) {
swap(str[j], str[j+1]);
cout << str << endl;
}
}
int factorial(int n)
{
if (n != 1) return n*factorial(n-1);
}
int main()
{
string str;
cout << "Enter string: ";
cin >> str;
cout << str.length() << endl;
int fact = factorial(str.length());
int a = fact/((str.length()-1));
for (int i = 0; i < a; i++) {
permuteString(str, (str.length()-1));
}
}