I'm trying to build a function that takes in a c-string and a pointer to an array of character pointers and should return the number of tokens found while putting each token into an array of pointers to character pointers. For example if I pass in the string ls -l file, it should put into a an array of c-strings that has each word in a line (args[1] = "I\0", args[2] = "am\0", args[3] = "the\0", args[4] = "test\0", args[5] = "string\0"). Thanks for any help!
Here's what I have so far, but I am getting memory access violations:
#include <iostream>
using namespace std;
int MakeArg(char [], char** []);
int main()
{
char str[] = "I am the test string";
char** argv;
int argc;
argc = MakeArg(str, &argv);
cin.ignore();
cout << "\nPress enter to quit.";
cin.ignore();
return 0;
}
int MakeArg(char s[], char** args[])
{
int word = 1;
for (int i = 0; s[i] != '\0'; i++) //iterates through every character in s
{
*args[word][i] = s[i]; //adds each character to word
if (s[i] == ' ') //when a space is found
{
*args[word][i] = '\0'; //it replaces it with a nullbyte in args
word++; //and moves on to the next word
}
}
return word; //returns number of words
}
Related
I am receiving an error from the following code when I try to dynamically allocate the array (seen after my attempt to incrementing through each letter in the users array using the bool function). This is the error:
main.cpp: In function ‘Word* splitSentene(std::string, int&)’:
main.cpp:81:32: error: cannot convert ‘std::string* {aka std::basic_string*}’ to ‘Word*’ in assignment
words = new string[i];
I am trying to count how many words the user inputs and dynamically allocate an array for the string of words. This is my code thus far:
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word * splitSentence(const string words, int &size){};
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word * splitSentene(const string words, int &size)
{
bool flag = true;
int num = 0;
for (int i = 0; i < words.length() + 1; i++)
{
//test for white space, then when you hit the first alphabetical character after a space,
//increment up the size of the array
if (isspace(words[i]))
flag = true;
if (isalpha(words[i]));
{
if (flag == true)
{
flag = false;
cout << words[i++];
}
}
// Dynamically allocate the array for the words
Word *sentence = nullptr;
sentence = new string[i];
}
}
Here are the pt 1 instructions for further clarification:
PT. 1) Write a function that takes in an English sentence as one string. This function should first calculate how many “words” are in the sentence (words being substrings separated by whitespace). It should then allocate a dynamic array of size equal to the number of words. The array contains Word structures (i.e. array of type Word). The function would then store each word of that sentence to the english field of the corresponding structure. The function should then return this array to the calling function using the return statement, along with the array size using a reference parameter.
This function should also remove all capitalization and special characters other than letters. Implement the function with the following prototype:
Word * splitSentence(const string words, int &size);
This is my first post here, so I will appreciate any input on how to dynamically allocate the array and format it (if I have successfully coded how to count the words in the sentence the user inputs). If more information needs to be provided, let me know!
The compiler error is because you are trying to assign a string[] array to a Word* pointer. You need to allocate a Word[] array instead.
You also have other errors in your code:
You have an erroneous {} at the end of the declaration of splitSentence().
You misspelled splitSentene in the defintion of splitSentence().
You have an erroneous ; on if (isalpha(words[i]));
You are not return'ing the array that you allocate.
In fact, you are not even following the instructions properly at all. You are not "calculating how many words are in the sentence" BEFORE allocating the array (you tried, but you are doing the allocation in the wrong place), and you are not filling the array at all, let alone "removing all capitalization and special characters other than letters".
Try something more like this:
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word* splitSentence(const string words, int &size);
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word* splitSentence(const string words, int &size)
{
bool flag = true;
int num = 0;
char ch;
for (int i = 0; i < words.length(); ++i)
{
ch = words[i];
if (isalpha(ch))
{
if (flag)
{
flag = false;
++num;
}
}
else if (isspace(ch))
{
flag = true;
}
}
Word *sentence = new Word[num];
int index = -1;
flag = true;
num = 0;
for (int i = 0; i < words.length(); ++i)
{
ch = words[i];
if (isalpha(ch))
{
if (flag)
{
flag = false;
++num;
++index;
}
if (isupper(ch))
{
ch = tolower(ch);
}
sentence[index].english += ch;
}
else if (isspace(ch))
{
flag = true;
}
}
size = num;
return sentence;
}
Live Demo
That being said, this will be much easier to implement splitSentence() if you could use std::istringstream and std::vector and other C++ idioms, instead of using C idioms, eg:
#include <iostream>
#include <sstream>
#include <cctype>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word* splitSentence(const string words, int &size);
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word* splitSentence(const string words, int &size)
{
istringstream iss(words);
vector<string> vec;
string s;
while (iss >> s)
{
remove_if(s.begin(), s.end(),
[](unsigned char ch){ return !isalpha(ch); });
if (!s.empty())
{
transform(s.begin(), s.end(), s.begin(),
[](unsigned char ch){ return tolower(ch); });
vec.push_back(s);
}
}
Word *sentence = new Word[vec.size()];
transform(vec.begin(), vec.end(), sentence,
[](const string &s){
Word w;
w.english = s;
return w;
}
);
size = vec.size();
return sentence;
}
Live Demo
A C++ program which read data from a text file. Suppose text file contains a
paragraph about any topic. Your program asks user to enter file name without extension. Now, a
user defined function (name: ReadWordByWord()) reads all data word by word and store in a
character type array with dynamically grows according to the data.
Finally, declare a user-defined function (name: SaveInReverse()) which stores this text into a
text file (name is entered by user) in reverse order of words e.g. last words will be stored at start,
then 2nd last word, 3rd last word etc. of the original document.
And here is what I've done so far... Here I am not using the delete command, that if I use will cause an error- a heap error. How can I accomplish that first? And then what are any tips to improve this program.
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
char* readWordByWord(char * old)
{
int coun = 0;
for (int i = 0; old[i] != '\0'; i++) // to find the length of word
{
coun++;
}
char *newArr = new char[coun + 1];
strcpy(newArr, old);
//delete[]old; // this is where i am putting delete command to delete the previous i.e old array and then return the new one
return newArr;
}
int size = 100;
int main()
{
fstream fin;
string forCopy[1000];
int index = 0;
fin.open("file.txt");
char *p = new char[size];
while (fin >> p)
{
p = readWordByWord(p);
//cout << p<<endl;
forCopy[index++] = p;
/*for (int i = 0; p[i] != '\0'; i++)
{
}*/
}
for (int i = index - 1; i > 0; i--)
cout << forCopy[i] << " ";
delete[]p;
p = NULL;
fin.close();
return 0;
}
I've made it from start again (must not include newlines since only a paragraph required):
#include <iostream>
#include <fstream>
#include <string>
void reverse(char *begin, char *end) { // reverses a word
char temp;
while (begin < end) {
temp = *begin;
*begin++ = *end;
*end-- = temp;
}
}
void reverseParagraph(char *arg) { // reverses each word of the paragraph
char *word_begin = arg;
char *temp = arg;
while (*temp) {
temp++;
if (*temp == '\0')
reverse(word_begin, temp - 1);
else if (*temp == ' ') {
reverse(word_begin, temp - 1);
word_begin = temp + 1;
}
}
reverse(arg, temp - 1);
}
int main() {
std::ifstream file("file.txt");
std::string fileData = "";
while(getline(file, fileData)); // counting the number of letters for memory allocation
size_t len = fileData.length();
char *str = new char[len + 1];
strcpy(str, fileData.c_str());
reverseParagraph(str); // reverse the entire character pointer
std::cout << str << std::endl; // displays for testing
std::ofstream fileOut("out.txt");
fileOut << str << std::endl; // saving the output into another file
fileOut.close();
delete[] str;
file.close();
return 0;
}
This program firstly gets the containing data of a file and then assigns into a variable. The variable is then converted into character (pointer) after getting the string length.
After that, it recursively reverses the position each word of the fileData and finally it displays. The modified data is thereafter printed into another file.
doing some exrecises for upcoming test. a bit stuck in this one.
"Write a program that asks the user for two strings and checks and prints a message if the second string is contained cyclic in the first string. The cyclic containment means that either the second string appears normally within the first string or the second string appears so that its prefix appears at the end of the first string and the continuation appears at the beginning of the first string".
You can assume that the strings contain only lowercase letters.
String functions are only allowed are : strlen, strcpy, strcmp, strcat
for example:
String A: itisaniceday
String B: sanic
Is a regular occurrence
String A: itisaniceday
String B: dayit
It's a cyclic occurence.
what I did so far:
#include <iostream>
#include <string.h>
using namespace std;
#define Max 128
int isCyclic(char* str1, char* str2);
int main()
{
char* str1 = new char[Max];
char* str2 = new char[Max];
cout << "Please enter two strings:" << endl;
cin >> str1 >> str2;
cout << isCyclic(str1, str2) << endl;
delete[] str1;
delete[] str2;
}
int isCyclic(char* str1, char* str2)
{
int s1 = strlen(str1);
int s2 = strlen(str2);
if (s1!=s2) // if string size is diffrent - they are not contained cyclic
{
return 0;
}
}
You will need two loops, first one over string 1 which is our starting point in string 1 for comparison and second one over string 2 which will be matched to string 1 in a cyclic way. If we reach the end of string 1 and still some characters are left in string 2 then cycle through string 1 starting from index 0.
#include <stdio.h>
#include <iostream>
#include <string.h>
// Should be avoided in general. Use scope resolution instead.
using namespace std;
char* isCyclic(char* s1, char* s2){
int s1_size = strlen(s1);
int s2_size = strlen(s2);
// s1 must contain s2
if(s2_size > s1_size)
return "No Occurence";
for(int i = 0; i < s1_size; i++){
int current = i;
// Boolean to track if we are currently cycling through s1
bool inCycle = false;
int j = 0;
for(; j < s2_size; j++, current++){
// character wise comparision
if(s2[j] != s1[current])
break;
if(! inCycle){
// start from first. Note that we are setting current = -1.
// as we will be incrementing it in the for loop.
if(current == s1_size - 1 && j < s2_size - 1){
current = -1;
inCycle = true;
}
}
}
if(j == s2_size){
if(inCycle)
return "cyclic";
else
return "regular";
}
}
return "No Occurence";
}
int main()
{
printf("Hello World\n");
char* s1 = "itisaniceday";
char* s2 = "dayitis";
cout<<"Occurence Type: "<<isCyclic(s1, s2)<<endl;
return 0;
}
Here is a solution for the second part of the problem (cyclic part). I simply go through all of the characters in the first string and checked if they are the beginning of a cyclic appearance of the second string.
To check that I used % (the modolu operation) if you don't know what it dose then you really need to learn it now.
Also I used bool instead of int because numbers are confusing (and cursed).
#include <iostream>
#include <string.h>
using namespace std;
#define Max 128
bool isCyclic(char* str1, char* str2);
bool isCyclic(char* str1, char* str2,int start);
int main()
{
char* str1 = new char[Max];
char* str2 = new char[Max];
cout << "Please enter two strings:" << endl;
cin >> str1 >> str2;
cout << isCyclic(str1, str2) << endl;
delete[] str1;
delete[] str2;
}
bool isCyclic(char* str1, char* str2) {
for(int i = 0; i < strlen(str1); i++) {
if(str1[i] == str2[0] && isCyclic(str1,str2,i)) {
return true;
}
}
return false;
}
bool isCyclic(char* str1, char* str2,int start)
{
int containingStrLen = strlen(str1);
for(int i = 0; i < strlen(str2); i++) {
if(str1[(start + i)%containingStrLen] != str2[i]) {
return false;
}
}
return true;
}
There are some things missing in this code still:
1) The first part of the problem (it can easily be derived from this code).
2) Some size validation such as making sure that str1 is bigger then str2 before using is cyclic. And that the strings are smaller then Max (I assume).
3) A proper result print.
Good luck in your exam :)
There's a simple trick : if you duplicate the string's prefix at its own end, the problem becomes a straight substring search as a cyclic match would be recomposed at the end. It also handles the corner case where the substring loops back on itself, such as "looploop" inside of "loop".
So here's how you'd do it in broken C-ish dialect:
bool containsCyclic(char const *string, char const *substring) {
std::size_t const stringLen = std::strlen(string);
std::size_t const substringLen = std::strlen(substring);
// Too long a substring wouldn't fit in the string
if(substringLen > 2 * stringLen)
return false;
// Concatenate `string` with its own substring-long prefix
char *const loopedString = new char[stringLen + substringLen + 1];
std::strcpy(loopedString, string);
{ // Partial reimplementation of std::strncpy(loopedString, string, substringLen)
char const *src = string;
char *dest = loopedString + stringLen;
for(std::size_t count = 0; count < substringLen; ++count)
*dest++ = *src++;
*dest = '\0';
}
{ // Partial and naïve reimplementation of std::strstr(loopedString, substring)
for(char const *start = loopedString; start < loopedString + stringLen; ++start) {
// Check if substring is present at this offset
char const *s1 = start;
char const *s2 = substring;
while(*s2 != '\0' && *s1 == *s2)
++s1, ++s2;
if(*s2 == '\0') {
// We found a complete match of substring inside loopedString
delete[] loopedString;
return true;
}
}
}
// No match found
delete[] loopedString;
return false;
}
And just for kicks, here it is in C++:
bool containsCyclicCpp(std::string const &string, std::string const &substring) {
std::string const loopedString = string + string.substr(0, substring.size());
return loopedString.find(substring) != std::string::npos;
}
See it live on Coliru (with tests!)
The problem enlies with printf(stringOut). It prints an empty array. The function halfstring appears to work correctly but the string it builds never makes it to main.
int main(int argc, char *argv[])
{
char stringIn[30] = "There is no cow level.\0";
char stringOut[sizeof(stringIn)];
halfstring(stringIn, stringOut);
printf(stringOut);
return 0;
}
halfstring is supposed to take every odd character in a char array and put it into a new char array without using ANY system-defined string functions (i.e. those found in the string.h library including strlen, strcat, strcpy, etc).
void halfstring(char stringIn [], char stringOut [])
{
int i = 0;
int modi;
while(stringIn[i] != '\0')
{
if(i % 2 != 0)
{
stringOut[i] = stringIn[i];
}
i++;
}
}
Inside the function halfstring you skipped the first and second characters of stringOut which probably are containing null characters when being declared this is the reason why you got nothing.
You can solve that by adding a new separate indice k for stringOut:
void halfstring(char stringIn [], char stringOut [])
{
int i = 0,k=0; // create a separate indice for stringOut
int modi;
while(stringIn[i] != '\0')
{
if(i % 2 != 0)
{
stringOut[k] = stringIn[i];
k++; // increment the indice
}
i++;
}
stringOut[k]='\0';
}
1) You don't need to NUL terminate a string literal:
char stringIn[30] = "There is no cow level.\0";
^^
2) Your second array (stringOut) results in something like:
{'T', garbage, 'e', garbage, 'e', garbage, 'a', garbage, 'e' ... };
You need to count the number of chars stored in the 2nd array:
void halfstring(char stringIn [], char stringOut [])
{
int i = 0;
int n = 0;
while(stringIn[i] != '\0')
{
if(i % 2 != 0)
{
stringOut[n++] = stringIn[i];
}
i++;
}
stringOut[n] = '\0';
}
There are several drawbacks in the program.
For starters there is no need to include the terminating zero in the string literal
char stringIn[30] = "There is no cow level.\0";
^^^^
because string literals already have the terminating zero.
Secondly usually standard string functions return pointer to the first character of the target string. This allows to chain at least two functions in one statement.
The first parameter is usually declares the target string while the second parameter declares the source string.
As the source string is not changed in the function it should be declared with the qualifier const.
And at last within the function there is used incorrect index for the target string and the string is not appended with the terminating zero.
Taking this into account the function can be written as it is shown in the demonstrative program below
#include <stdio.h>
char * halfstring( char s1[], const char s2[] )
{
char *p = s1;
while ( *s2 && *++s2 ) *p++ = *s2++;
*p = *s2;
return s1;
}
int main(void)
{
char s1[30] = "There is no cow level.";
char s2[sizeof( s1 )];
puts( halfstring( s2, s1 ) );
return 0;
}
Its output is
hr sn o ee.
I wrote this code to reverse strings. It works well, but when I enter short strings like "american beauty," it actually prints "ytuaeb nacirema2." This is my code. I would like to know what is wrong with my code that prints a random 2 at the end of the string. Thanks
// This program prompts the user to enter a string and displays it backwards.
#include <iostream>
#include <cstdlib>
using namespace std;
void printBackwards(char *strPtr); // Function prototype
int main() {
const int SIZE = 50;
char userString[SIZE];
char *strPtr;
cout << "Please enter a string (up to 49 characters)";
cin.getline(userString, SIZE);
printBackwards(userString);
}
//**************************************************************
// Definition of printBackwards. This function receives a *
// pointer to character and inverts the order of the characters*
// within it. *
//**************************************************************
void printBackwards(char *strPtr) {
const int SIZE = 50;
int length = 0;
char stringInverted[SIZE];
int count = 0;
char *strPtr1 = 0;
int stringSize;
int i = 0;
int sum = 0;
while (*strPtr != '\0') {
strPtr++; // Set the pointer at the end of the string.
sum++; // Add to sum.
}
strPtr--;
// Save the contents of strPtr on stringInverted on inverted order
while (count < sum) {
stringInverted[count] = *strPtr;
strPtr--;
count++;
}
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
cout << stringInverted << endl;
}
Thanks.
Your null termination is wrong. You're using == instead of =. You need to change:
stringInverted[count] == '\0';
into
stringInverted[count] = '\0';
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
Should use = here.
What is wrong with your code is that you do not even use strlen for counting the length of the string and you use fixed size strings (no malloc, or, gasp new[]), or the std::string (this is C++)! Even in plain C, not using strlen is always wrong because it is hand-optimized for the processor. What is worst, you have allocated the string to be returned (stringInverted) from the stack frame, which means when the function exits, the pointer is invalid and any time the code "works" is purely accidental.
To reverse a string on c++ you do this:
#include <iostream>
#include <string>
int main() {
std::string s = "asdfasdf";
std::string reversed (s.rbegin(), s.rend());
std::cout << reversed << std::endl;
}
To reverse a string in C99 you do this:
char *reverse(const char *string) {
int length = strlen(string);
char *rv = (char*)malloc(length + 1);
char *end = rv + length;
*end-- = 0;
for ( ; end >= rv; end --, string ++) {
*end = *string;
}
return rv;
}
and remember to free the returned pointer after use. All other answers so far are blatantly wrong :)