I'm learning to code and i want to do the following:
User runs program through CMD Ex:
cd C:\Program.exe P1 P2
The program will then complete its purpose. However I want to validate so if the user does the following certain responses occur:
P1 = Not a digit, or a +,-,e,E are the first or last character in argv[1] which returns "error".
P2 = The first character is not X and the second character is less than 2 or greater than 16. Which will return the response "error"
Cheers
You can easily check your arguments as they are simply strings. Storing the result as a std::string allows you to perform many operations to test your input. I've heavily commented the below code to help you understand the checks.
Everytime an error is occured, an error message is printed using fprintf to stderr. You should always print your errors to this stream as opposed to printing to stdout. This is because standard error is still seen by users without interfering with things that store the output from programs.
If the program does not return during checks, then your program can function knowing that your input is good.
#include <string>
int main (int argc, char *argv[]) {
//Validate
//If incorrect number of arguments, print error
if (argc != 3) { //3 as program name is argument, ie argv[1]
fprintf(stderr, "Not enough arguments");
return 1;
} else { //Check arguments
//Store arguments as strings to allow easy operations
std::string p1 = argv[1];
std::string p2 = argv[2];
//Check P1
if (! (p1.find_first_not_of( "0123456789" ) == std::string::npos) //if p1 is not made of 0-9
&& (p1.front() != '+' ) && (p1.front() != '-' ) //and the front char of p1 is none of the allowed characters
&& (p1.front() != 'e' ) && (p1.front() != 'E' ) ) //...then we have an error
{
fprintf(stderr, "Not a digit, or a +,-,e,E are the first or last character");
return 1;
}
//Check P2
std::string numeral = p2.substr(1, p2.length()); //store everything but first char into new string
int n = strtol(numeral.c_str(), NULL, 10); //use strtol to convert this to a number
if (p2.front() != 'X' //if front is not X, we have error
|| !numeral.find_first_not_of( "0123456789" ) == std::string::npos //or if substring is not a number, we have an error
|| (n < 2 || n >16) ) //or if n is either less than 2 or greater than 16, we have an error
{
fprintf(stderr, "The first character is not X and the second character is less than 2 or greater than 16");
return 1;
}
}
//program body here....
return 0;
}
Related
I'm learning C++, and I have no idea how I'm supposed to do the following.
In an assignment, we need to write a function that checks if the first two characters of a string are the same as the last two.
These are the limitations:
You cannot use std::string class or string function such as strlen. You must use either array or pointer for this function.
I tried this:
bool haveTheSameTwoChars(string str) {
char arr[] = str;
if (sizeof(arr) < 3) {
return false;
}
else if (arr[0] == arr[sizeof(arr) - 3] && arr[1] == arr[sizeof(arr) - 2]) {
return true;
}
else {
return false;
}
}
But it won't accept str into the array.
However, if I were to put something in quotes in the place of str, it accepts it just fine, despite them both being strings.
What am I doing wrong?
Well, here's the breakdown of your problem:
You need to take input as an array or a pointer. For example:
bool isMatched( const char* str )
{
// ...
}
Now, you need to calculate the length of your string yourself. Revise the loops and devise something that gives you the length of a null terminated string. C-strings are null-terminated i.e. '\0' so you can end your loop when you encounter null character. For example:
int len = 0;
while ( str[len] != '\0' ) len++;
That's just an idea. Do your own research and calculate the string length correctly.
The rest is just a comparison of first and last two characters using if. :)
I'm sure you can put things together and revise your study material a bit to solve this.
Best of luck!
Happy coding!
When you're not allowed strlen, it is a strong hint that the problem can be solved without caring about the length of the string.
Let's do that:
First, you should have the prototype (no strings allowed, right?)
bool haveTheSameTwoChars(const char* str)
Then, verify that the string has at least two characters
if (!str || !str[0] || !str[1])
return false;
Then you find the end of the string:
const char* end = str;
while (*end)
end++;
Then move back two characters, so end points to the first of the last two characters:
end -= 2;
(This is safe since we first checked that there are at least two characters.)
Then compare
return str[0] == end[0] && str[1] == end[1];
Your professor wants you to use a const char* as the function parameter, that is, model a string as a pointer to the first character in the string, where the string finishes with a 0. (We call this NUL-termination).
So your function is
bool haveTheSameTwoChars(const char* s)
You then need to roll your own version of strlen1 to calculate the number of characters in the string up to and not including the NUL:
#include <cstddef> // for std::size_t
std::size_t strlen(const char *s) {
const char *p = s;
while (*s) ++s;
return s - p;
}
After which, it's a simple case, given the length l say, of dealing with a couple of edge cases and the general case:
If l is 0 or 1, return false.
If l is 2, return true.
If l is greater than 2 then something similar to how you have it in the question will suffice, remembering that my l is one less than yours.
Note that C++ does not support variable length arrays, so char arr[] = str; is not valid C++, and sizeof is a compile-time operator so would only give you the size of an actual array type, not an array that's decayed to a pointer type.
1 No professional programmer would dream of doing that. A compiler might optimise strlen down to a machine word-based algorithm, i.e. consider multiple bytes simultaneously.
Here is some sample code for your purpose
bool haveTheSameTwoChars(const char* p) {
if(!p || !*p)
return false;
int len = -1;
while(p[++len]);
if(p[0] == p[len-2] &&
p[1] == p[len-1])
return true;
return false;
}
This will return true if the string is "ABxxxAB" and false if "ABxxxBA". Rest you can tweak according to your desire.Thanks
Another approach uses a loop and a single pointer to iterate over each line saving the first and second characters to compare against the next to last (penultimate) and last (ultimate) characters in the string.
By using simple iteration over the character array, as long as it is nul-terminated, you don't have to worry about a separate loop to find the length, you simply grab/save the first two characters, and then iterate to the end of your string saving the prev/last characters as you go. When you hit the end of your string, all you need to do is compare the first against the last and the second against the next to last, e.g.
/* function iterates pointer through chars in 'line' saving
* the 1st & 2nd chara in 'beg` and 'next' and the penultimate and
* ultimate characters in 'prev' & 'last' and compares. returns 1 if
* 1st matches ultimate AND 2nd matches penultimate, 0 otherwise.
*/
int begmatchend (const char *line)
{
const char *p = line; /* pointer to line */
char beg = *p++, /* save for 1st char */
next = *p++, /* save for 2nd char */
prev = *p++, /* save for next to last char */
last = *p++; /* save for last char */
while (*p) { /* iterate over line setting prev/last as you go */
prev = last;
last = *p++;
}
if (beg == last && next == prev) /* test whether equal */
return 1;
return 0;
}
Then for a simple test, you can just feed your programs lines from a file calling begmatchend on each line and then output indication of which lines matched. Something simple like the following is one way:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstddef>
#define MAXC 1024
/* function iterates pointer through chars in 'line' saving
* the 1st & 2nd chara in 'beg` and 'next' and the penultimate and
* ultimate characters in 'prev' & 'last' and compares. returns 1 if
* 1st matches ultimate AND 2nd matches penultimate, 0 otherwise.
*/
int begmatchend (const char *line)
{
const char *p = line; /* pointer to line */
char beg = *p++, /* save for 1st char */
next = *p++, /* save for 2nd char */
prev = *p++, /* save for next to last char */
last = *p++; /* save for last char */
while (*p) { /* iterate over line setting prev/last as you go */
prev = last;
last = *p++;
}
if (beg == last && next == prev) /* test whether equal */
return 1;
return 0;
}
int main (int argc, char **argv) {
char line[MAXC] = "";
size_t n = 0;
std::ifstream f (argc > 1 ? argv[1] : "/dev/stdin");
if (!f.is_open()) {
std::cerr << "error: file open failed.\n";
return 1;
}
while (f.getline (line, MAXC, '\n')) {
if (begmatchend ((const char *)line))
std::cout << "line[" << std::setw(3) << n <<
"] 1st/ultimate matched, 2nd/penultimate matched.\n";
n++;
}
return 0;
}
Example Input
$ cat dat/linesbegend.txt
all good vikings go to valhalla
be a tide that will flow and eb
a quick brown fox jumps over the lazy dog
we can find the begin and end - eew
Example Use/Output
$ ./bin/beg_end_match dat/linesbegend.txt
line[ 0] 1st/ultimate matched, 2nd/penultimate matched.
line[ 1] 1st/ultimate matched, 2nd/penultimate matched.
line[ 3] 1st/ultimate matched, 2nd/penultimate matched.
Look things over and let me know if you have any questions.
I wanted to write this code without using atoi.
edit* question did not make sense for readers and it was too long. sorry for being vague with everything.
Several fundamental problems:
if (firsttimeThru)
{
firsttimeThru = false;
int result = number(auctionString, stringPosition);
if (result > 0)
{
///////////////////////////////////////////////////
// too early!
///////////////////////////////////////////////////
return true;
}
else
{
return false;
}
If you return here, you have checked, if a number follows 'L'/'l', but there might yet follow something - valid or not...
default:
return false;
// break; // not necessary (unreachable anyway); you return previously, don't you?
You will now reject any input, including the 'B' (provided you did not return as shown above...).
Assuming you iterate over the whole loop successfully (skipping the premature return), you need a default return value:
for(...) {}
// assuming you returned on error previously:
return true;
Now how to do better? I am now not pretty sure what you really are after, so I try to deduce a pattern from your example string "L500B50B+100":
L or l followed by any non-negative integral number followed by another single character followed by another non-negative integral followed by another letter followed by + followed by another non-negative integral...
bool isValidEbayListingString(string auctionString)
{
// i prefer operating on character data (allows to use strtol),
// you could use the string's iterator instead:
#if 0
std::string::const_iterator data = auctionString.begin();
// instead of checking for *data ==/!= 0, you then need
// to check for data ==/!= auctionString().end()
// additionally, you explicitly need to check for empty string!
#else
char const* data = auctionString.c_str();
#endif
if(*data == 'L' || *data == 'l')
// checks for string length being 0, too, as *data would be 0 then...
{
++data;
// now non-negative integral required:
#if 0
char* end;
unsigned long number = strtoul(data, &end, 10);
if(end == data || errno == ERANGE)
// no data or too large number;
// how many digits do you want to allow???
// if need be, consider unsigned long long and strtoull...
{
return false;
}
#else
// assuming you do not need the number, much easier:
if(!*data) // need at least one digit
{
return false;
}
while(*data && isdigit((unsigned char)*data))
++data;
// pack this piece of code into a function for reuse...
#endif
if(*data && *data != 'L' && *data != 'l')
// a letter must follow, but non of L/l
{
++data;
// check for digits just as above (call the function)...
if(*data && *data != 'L' && *data != 'l' && data[1] == '+')
// another letter except L/l, next one must be '+'
{
data += 2;
// check for digits just as above...
return *data == 0; // we must now have reached the string's end!
}
}
}
// any other case:
return false;
}
If I guessed the wrong pattern, you'll need some adjustments, of course...
Let's assume that I have the following file: wow.txt which reads
4 a 1 c
and what I want to do is I would like to output the following:
d 1 a 3
change the integer to the corresponding alphabet (d is 4th letter, a is 1st letter
in the alphabet), and alphabet letter to the corresponding integer
(a is 1st letter in the alphabet, c is the 3rd letter in the alphabet)
I started with the following code in C++.
int main()
{
ifstream inFile;
inFile.open("wow.txt");
ofstream outFile;
outFile.open("sample.txt");
int k, g;
char a, b;
inFile>>k>>a>>g>>b;
outFile<<(char)(k+96)<<(int)a-96<<(char)(g+96)<<(int)b-96
}
inFile.close();
outFile.close();
}
but then here, I could only do it because I knew that the text in wow.txt
goes integer, character, integer, character.
Also, even if I knew the pattern, if the text in wow.txt is super-long, then
there's no way I could've solved the problem using the method I used, manually
typing in each input (Defining k, g as integers, a, b as characters, and
then doing inFile>>k>>a>>g>>b;)
Also, I didn't know know the pattern, there's no way
I could've solved it. I was wondering if there's a C++
function that reads the input from the given text file and determines its type, so
that I could attack the this type of problem in the more general case.
I'm very new to C++ programming language (or programming in general),
so any help about this would be greatly appreciated.
The term you're searching for is parsing. It is the idea of taking in text and transforming it into something meaningful. Your C++ compiler, for example, does exactly that with your program's code -- it reads in text, parses it into a series of internal representations that it does transforms on, then outputs binary code that, when run, carries out the intent of the code you wrote.
In your case, you want to turn the problem on its head -- instead of telling the input stream what to expect next from the file, you simply extract everything as text, and then figure it out yourself (you let the stream tell you what's there). If you think about it, it's text (or rather, binary data, but close enough) all the way down anyway, even when you're asking for, say, an integer to be read from the stream -- the stream does the integer parsing for you in that case, but it's still just text being parsed.
Here's some example code (untested) to get you started:
std::ifstream fin("wow.txt");
// Read everything in (works well for short files; longer
// ones could be read incrementally (streamed), but this
// adds complexity
fin.seekg(0, fin.end);
std::size_t size = fin.tellg();
fin.seekg(0, fin.beg);
std::vector<char> text(size);
fin.read(&size[0], size);
fin.close();
// Now 'tokenize' the text (into words, in this case characters)
enum TokenType { Letter, Number };
struct Token {
const char* pos;
std::size_t length;
TokenType type;
};
std::vector<Token> tokens;
for (const char* pos = &text[0]; pos != &text[0] + text.size(); ++pos) {
if (*pos >= 'a' && *pos <= 'z') {
// Letter! (lowercase)
Token tok = { pos, 1, Letter };
tokens.push_back(tok);
// TODO: Validate that the next character is whitespace (or EOF)
}
else if (*pos >= '0' && *pos <= '9') {
Token tok = { pos, 1, Number };
while (*pos >= '0' && *pos <= '9') {
++pos;
++tok.length;
}
tokens.push_back(tok);
// TODO: Validate that the next character is whitespace (or EOF)
}
else if (*pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n') {
// Whitespace, skip
// Note that newlines are normally tracked in order to give
// the correct line number in error messages
}
else {
std::cerr << "Unexpected character "
<< *pos
<< " at position "
<< (pos - &text[0]) << std::endl;
}
}
// Now that we have tokens, we can transform them into the desired output
std::ofstream fout("sample.txt");
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
if (it->type == Letter) {
fout << static_cast<int>(*(it->pos) - 'a') + 1;
}
else {
int num = 0;
for (int i = 0; i != tok.length; ++i) {
num = num * 10 + (tok.pos[i] - '0');
}
// TODO: Make sure number is within bounds
fout << static_cast<char>(num - 1 + 'a');
}
fout << ' ';
}
fout.close();
I was trying to solve a programming problem of some site and this one had the following statement:
Read a string and parse it as a number, char 'l' can be considered as number 1 and chars 'o' and 'O' can be considered as number 0, commas and spaces will be accepted in the input but ignored, if any other character is found then output error...
So... since there can be spaces in the lines, I used gets (the documentation says it removes the new line and puts a terminator)...
My sequence of IF test if it is a number, then if its an acceptable letter, then checks if it is not a comma or a space... And I found out that it was almost always entering in the last IF even though there wasn't any character that should lead it there so I changed the printf inside it to print the
printf("%d error", st[k]);
And it outputs 13: carriage return... I tried this compiler here
#include <cstdio>
#include <cstring>
#include <cstdlib>
int main()
{
char st[100];
char buf[100];
int k, i;
long long int num;
ops: while(gets(st))
{
for(k = i = 0; st[k]; k++)
if(st[k] >= '0' && st[k] <= '9')
buf[i++] = st[k];
else if(st[k] == 'o' || st[k] == 'O')
buf[i++] = '0';
else if(st[k] == 'l')
buf[i++] = '1';
else if(st[k] != ',' && st[k] != ' ')
{
printf("error\n");
goto ops;
}
// remaining code comes here...
}
The input sample had the following lilnes:
lo6
234,657
hi
,,,,,5,,5, 4
2200000000
00
Should I use other function to read instead?
Any suggestions on how to avoid this damn Carriage Return?
The statemente for the problem can be seen here if you want more detail
Thanks
EDIT:
I'm asking that because there seem to be a difference between the compiler I'm using and the compiler the website was using, once I submitted a code that wasn't generating the correct output on mine but I thought the code was correct... and it passed. Then after it, I tried the code on a linux virtual machine and also correct but my gcc on windows failed... some characters were completely away from where they should be
The thing is:
The preferred method of line input is getline. If you do not know the width of the input beforehand, getline will allocate space for you if you set the buffer pointer to NULL.
Since you indicate you have some experience in C, the following will show you how to step through an input string and parse it in the manner you want. While there are many ways to handle parsing strings, it is hard to beat assigning a pointer to the beginning of the string and then advancing down the string until you reach the null-terminating character (unsigned 0, or char '\0'). If you have any questions after looking it over, just ask:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]) {
char *buffer = NULL;
size_t n = 0;
ssize_t len;
char *ptr = NULL;
char *output = NULL;
int idx = 0;
printf ("\nEnter your string below: ([ctrl + d] on blank line to end)\n");
while ((len = getline (&buffer, &n, stdin)) != -1) {
ptr = buffer;
idx = 0;
output = malloc (sizeof (char) * len);
while (*ptr != 0) {
if (*ptr >= 48 && *ptr <= 57) output [idx++] = *ptr;
if (*ptr == 'I') output [idx++] = '1';
if (*ptr == 'o' || *ptr == 'O') output [idx++] = '0';
ptr++;
}
output [idx] = 0;
printf ("\n valid output: %s\n\n", output);
free (output);
}
return 0;
}
output:
Enter your string below: ([ctrl + d] on blank line to end)
This sting has 12345 aeiou AEIOU,,,,,commas, and 99, to end.
valid output: 123450100990
This is a homework assignment first off.
We have to create a "common application-programming model in UNIX/Linux known as the filter".
I'm stuck on reading the input passed through as arguments (it's all I ever seem to have trouble on).
For example, the cmd is open and the following line is entered:
program -isomebinaryfile.bin
I need to determine what the first letter is after the hyphen (-) and so on and so forth.
Is scanf what I would be using? My main is set up to be able to accept arguments:
int main (int argc, char *argv[])
{
FILE *inf = NULL;
char *arg = argv[0];
}
Can someone give me a little help?
Unless your assignment is only to handle processing of arguments, you may want to look up getopt - it's a standard library parser for arguments.
As for the meat of your question, there are a lot of options, and you could use sscanf as part of it, but you don't have to.
To parse the one argument you mentioned, you need to do the following: check if the argument begins with -i, grab the data out of the argument.
The easiest way to check if the argument begins with -i is:
if (argv[1][0] == '-' && argv[1][1] == 'i')
Alternatively, if you have a lot of argument options, all beginning with '-', you may want something like:
char * i = NULL;
char * o = NULL;
char * s = NULL;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'i':
i = argv[i][2];
break;
case 's':
s = argv[i][2];
break;
case 'o':
o = argv[i][2];
break;
default:
cerr << "Unknown option: " << argv[i][1];
}
} else {
cerr << "Error: all options must begin with '-'";
}
Note, I'm using argv[1], not 0. argv[0] is always the name of the executable.
The fastest way to extract the rest of the argument is simple pointer arithmetic:
char * filename = argv[1] + 2; // (Or you could equivalently say = &argv[1][2]
This is most efficient - it reuses the strings that are already in argv. If you're planning on changing the strings around, you'd do better with strcpy:
char * filename = (char *)malloc(strlen(argv[1]) - 2);
strcpy(filename, argv1 + 2);
// and eventually you'd have to free(filename)...
Play around and experiment with all the string functions. You'll find them essential to all of your later programs.
You need to use getopt. The manual page has an example.
argv is an array of strings. You can loop over them like
for (int i=1; i<argc; i++) { // skip argv[0] as that's this program's name
const char* arg = argv[i];
}
Once you have the string for a particular argument, you can use the string manipulation functions from <string.h>
if (arg[0] == '-' && strlen(arg) > 0) {
arg++; // advance past the leading '-'
if (strcmp(arg, "command_one") == 0) {
// handle command_one
}
else if (strcmp(arg, "command_one") == 0) {
....
else {
printf("Error: unexpected command %s\n", arg);
}
Get arguments from argv ("argument vector"). In your example, argc and argv will be as follows:
argc == 2
argv[0] == "cmd"
argv[1] == "-isomebinaryfile.bin"
Finding the first letter after the hyphen in argv[1] is a simple loop.