creating a function to match a string in the main - c++

This is a group assignment and it's become rather difficult to the point our professor has extended the project by 1 week. there are 50 stages/tests, we've only been able to reach up to stage 11 and then the function fails.
this function is in our .cpp file (we're positive it's this function causing the problem's because when we change parts of it, it affects stage 11 which we've passed).
int segment::match(const char word[]) {
int i;
cout << data[0];
data[0] == "OOP";
cout << data[0];
for(i=0;i<NUM_MAX;i++) {
cout << "word = " << &word[i] << " data[i] = " << data[i];
if(strstr(&word[i],data[i])!= NULL)
break;
}
return i==NUM_MAX ? 1 : i-1;
and from the main.cpp (provided to us as the assignment) this is the what we are trying to accomplish
Passed test 11...
Your match( ) return value ----> -1
Actual match( ) return value --> -1
Press the ENTER key to continue...
word = OOP data[i] =
Failed while testing the match( )
function... Failed on test 12...
Your match( ) return value ----> -1
Actual match( ) return value --> 1
Press the ENTER key to continue...
You passed 11/50 tests...
Your program is 22.00% complete!
Your program still needs some work!
Keep at it!
what the function is suppose to do is check for "oop" and if it isn't there it exits with -1, and if it is there it should return true with 1.
I guess what I'm asking is how do I make that function that it returns both -1 and 1 in the proper order?
If you would like access to the main.cpp and segement.cpp i can upload that as files somewhere because they're very long and I did not want to cram the post.
Any help is appreciated, thank you.
EDIT*
Here is the full code that we have
http://jsfiddle.net/h5aKN/
The "html" section has the segement.cpp which is what we built.
and the jscript section has the a2main.cpp which is what our professor built.

data[0] == "OOP"; is probably not what you want to do. The double = (==) tests for equality, so here you're testing if the item at the first index of data (data[0]) and the character string "OOP" are equal.
In the running of the test, you are cout'ing: word = OOP data[i] =, which means that word[i] is probably defined correctly, but data[i] is not. This goes back to the usage of the equivalence test above.
If you set initialize data correctly, (correctly meaning allocating the memory correctly, I don't know where data is instantiated), then the test would likely return -1, as it would get a non NULL pointer from the strstr() call (assuming that data is the correct type), i would be 0 on breaking, and the ternary operator would yield i-1, = -1.
So fix the initialization / assignment of the data variable
And if you're not limited to c style strings (char arrays), I'd use the std::string type and its associated methods (see the c++ string reference if you haven't already). Usually much nicer to work with

If you are passing a list of words to the function:
As the use of (strstr(&word[i],data[i])) suggests you are looking for a string inside another string. Thus you are looping over a list of strings (words).
Then this looks wrong:
int segment::match(const char word[]) {
Here you are passing one word.
Its impossable to tell what it should be, but a guess would be:
int segment::match(const char* word[]) {
// ^^^^^
But to be honest the whole thing is rather ugly C++. If you were writting C I would say fine, but if you had been writing C++ correctly the type system would have saved you from all these problems. Use std::string to represent words.

Related

Unexpected output in C++

This is not a problem with programming contest but with the language C++.
There is an old programming problem on codeforces. The solution is with C++. I already solved in Python but I don't understand this behavior of C++. In my computer and on onlinegdb's C++ compiler, I get expected output but on codeforces judge, I get a different output.
If interested in the problem : http://codeforces.com/contest/8/problem/A
It's very simple and a small read. Though Reading it is not required for the question.
Task in Short:
Print("forward") if string a is found in string s and string b is also found in s
Print("backward") if string a is found in reverse of string s and string b is also found in reverse of s
Print("both") if both of above are true
Print("fantasy") if both of above are false
#include<bits/stdc++.h>
using namespace std;
#define int long long
//initializing all vars because blogs said uninitialized vars sometimes give unexpected result
string s="", a="", b="";
bool fw = false;
bool bw = false;
string now="";
string won="";
int pa=-1, pb=-1, ra=-1, rb=-1;
signed main()
{
//following 2 lines can be ignored
ios_base::sync_with_stdio(false);
cin.tie(NULL);
//taking main input string s and then two strings we need to find in s are a & b
cin >> s >> a >> b;
//need reverse string of s to solve the problem
string r = s;
reverse(r.begin(), r.end());
//pa is index of a if a is found in s else pa = -1 if not found
pa = s.find(a);
//if a was a substring of s
if (pa != -1) {
//now is substring of s from the next letter where string a was found i.e. we remove the prefix of string till last letter of a
now = s.substr(pa + a.size(), s.size() - (pa + a.size()));
//pb stores index of b in remaining part s i.e. now
pb = now.find(b);
//if b is also in now then fw is true
if (pb != -1) {
fw = true;
}
}
//same thing done for the reverse of string s i.e. finding if a and b exist in reverse of s
ra = r.find(a);
if (ra != -1) {
won = r.substr(ra + a.size(), r.size() - (ra + a.size()));
rb = won.find(b);
if (rb != -1) {
bw = true;
}
}
if (fw && bw) {
cout << "both" << endl;
}
else if (fw && !bw) {
cout << "forward" << endl;
}
else if (!fw && bw) {
cout << "backward" << endl;
}
else {
cout << "fantasy" << endl;
}
return 0;
}
For input
atob
a
b
s="atob", a="a", b="b"
Here reverse of atob is bota.
a is in atob.
So, string now = tob.
b is in tob so fw is true.
Now a is in bota.
So, string won = "" (empty because nothing after a). So, b is not in won.
So, rw is false.
Here answer is to print forward and in C++14 on my PC and onlinegdb, the output is forward but on codeforces judge, it's both.
I did many variations of the code but no result.
Finally I observed that if I run my program on PC and don't give any input and terminate the program in terminal with Ctrl-C, it prints both which is strange as both should only be printed when both fw and rw are true.
What is this behavior of C++?
Let's dissect this code and see what problems we can find. It kind of tips over into a code review, but there are multiple problems in addition to the proximate cause of failure.
#include<bits/stdc++.h>
Never do this. If you see it in an example, you know it's a bad example to follow.
using namespace std;
Fine, we're not in a header and brevity in sample code is a reasonable goal.
#define int long long
Oh no, why would anyone ever do this? The first issue is that preprocessor replacement is anyway prohibited from replacing keywords (like int).
Even without that prohibition, this later line
int pa=-1, pb=-1, ra=-1, rb=-1;
is now a deliberate lie, as if you're obfuscating the code. It would have cost nothing to just write long long pa ... if that's what you meant, and it wouldn't be deceptive.
//initializing all vars because blogs said uninitialized vars sometimes give unexpected result
string s="", a="", b="";
But std::string is a class type with a default constructor, so it can't be uninitialized (it will be default-initialized, which is fine, and writing ="" is just extra noise).
The blogs are warning you about default initialization of non-class types (which leaves them with indeterminate values), so
bool fw = false;
is still sensible.
NB. these are globals, which are anyway zero-initialized (cf).
signed main()
Here are the acceptable faces of main - you should never type anything else, on pain of Undefined Behaviour
int main() { ... }
int main(int argc, char *argv[]) { ... }
Next, these string positions are both (potentially) the wrong type, and compared to the wrong value:
ra = r.find(a);
if (ra != -1) {
could just be
auto ra = r.find(a);
if (ra != std::string::npos) {
(you could write std::string::size_type instead of auto, but I don't see much benefit here - either way, the interface, return type and return values of std::string::find are well-documented).
The only remaining objection is that none of now, won or the trailing substring searches correspond to anything in your problem statement.
The above answer and comments are way more enough information for your question. I cannot comment yet so I would like to add a simplified answer here, as I'm also learning myself.
From the different outputs on different compilers you can trackback the logic and found the flow of code is differ in this line:
if (rb != -1) {
Simply adding a log before that line, or using a debugger:
cout << "rb:" << rb << endl;
You can see that on your PC: rb:-1
But on codeforces: rb:4294967295
won.find(b) return npos, which mean you have an assignment: rb = npos;
This is my speculation, but a possible scenario is:
On your PC, rb is compiled as int (keyword), which cannot hold 4294967295, and assigned to -1.
But on codeforces, rb is compiled as long long, follow the definition, and 4294967295 was assigned instead.
Because you redefine the keyword int, which is advised again by standard of C++ programming language, different compiler will treat this line of code differently.

c_str() is only reading half of my string, why? How can I fix this? Is it a byte issue?

I am writing a client program and server program. On the server program, in order to write the result back to the client, I have to convert the string to const char* to put it in a const void* variable to use the write() function. The string itself is outputting the correct result when I checked, but when I use the c_str() function on the string, it is only outputting up until the first variable in the string. I am providing some code for reference (not sure if this is making any sense).
I have already tried all sorts of different ways to adjust the string, but nothing has worked yet.
Here are how the variables have been declared:
string final;
const void * fnlPrice;
carTable* table = new carTable[fileLength];
Here is the struct for the table:
struct carTable
{
string mm; // make and model
string hPrice; // high price
string lPrice; // low price
};
Here is a snipped of the code with the issue, starting with updating the string variable, final, with text as well as the resulting string variables:
final = "The high price for that car is $" + table[a].hPrice + "\nThe low
price for that car is $" + table[a].lPrice;;
if(found = true)
{
fnlPrice = final.c_str();
n = write(newsockfd,fnlPrice, 200);
if (n < 0)
{
error("ERROR writing to socket");
}
}
else
{
n = write(newsockfd, "That make and model is not in
the database. \n", 100);
if (n < 0)
{
error("ERROR writing to socket");
}
}
Unfortunately your code does not make any sense. And that may be your major problem. You should rewrite you code end eliminate the bugs.
Switch on all compiler warnings and eliminate the warnings.
Do not use new and pointers. Never
Do not use C-Style arrays. So, something with []. Never. Use STL containers
Always initialize all variables. Always. Even if you assign an other value in the next line
Do not use magic constants like 200 (The size of the string is final.size())
If an error happens then print the error text with strerror (or a compatible function)
Make sure that your array itself and the array values are initalized
To test your function, write to socket 1 (_write(1,fnlPrice,final.size()); 1 is equal to std::cout
There is no need to use the void pointer. You can use n = _write(newsockfd, final.c_str(), final.size()); directly
If you want a detailed answer here on SO then you need to post your compiled code. I have rewritten your function and tested it. It works for me and prints the complete string. So, there is a bug in an other part of your code that we cannot not see.

Recursive String Transformations

EDIT: I've made the main change of using iterators to keep track of successive positions in the bit and character strings and pass the latter by const ref. Now, when I copy the sample inputs onto themselves multiple times to test the clock, everything finishes within 10 seconds for really long bit and character strings and even up to 50 lines of sample input. But, still when I submit, CodeEval says the process was aborted after 10 seconds. As I mention, they don't share their input so now that "extensions" of the sample input work, I'm not sure how to proceed. Any thoughts on an additional improvement to increase my recursive performance would be greatly appreciated.
NOTE: Memoization was a good suggestion but I could not figure out how to implement it in this case since I'm not sure how to store the bit-to-char correlation in a static look-up table. The only thing I thought of was to convert the bit values to their corresponding integer but that risks integer overflow for long bit strings and seems like it would take too long to compute. Further suggestions for memoization here would be greatly appreciated as well.
This is actually one of the moderate CodeEval challenges. They don't share the sample input or output for moderate challenges but the output "fail error" simply says "aborted after 10 seconds," so my code is getting hung up somewhere.
The assignment is simple enough. You take a filepath as the single command-line argument. Each line of the file will contain a sequence of 0s and 1s and a sequence of As and Bs, separated by a white space. You are to determine whether the binary sequence can be transformed into the letter sequence according to the following two rules:
1) Each 0 can be converted to any non-empty sequence of As (e.g, 'A', 'AA', 'AAA', etc.)
2) Each 1 can be converted to any non-empty sequences of As OR Bs (e.g., 'A', 'AA', etc., or 'B', 'BB', etc) (but not a mixture of the letters)
The constraints are to process up to 50 lines from the file and that the length of the binary sequence is in [1,150] and that of the letter sequence is in [1,1000].
The most obvious starting algorithm is to do this recursively. What I came up with was for each bit, collapse the entire next allowed group of characters first, test the shortened bit and character strings. If it fails, add back one character from the killed character group at a time and call again.
Here is my complete code. I removed cmd-line argument error checking for brevity.
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
using namespace std;
//typedefs
typedef string::const_iterator str_it;
//declarations
//use const ref and iterators to save time on copying and erasing
bool TransformLine(const string & bits, str_it bits_front, const string & chars, str_it chars_front);
int main(int argc, char* argv[])
{
//check there are at least two command line arguments: binary executable and file name
//ignore additional arguments
if(argc < 2)
{
cout << "Invalid command line argument. No input file name provided." << "\n"
<< "Goodybe...";
return -1;
}
//create input stream and open file
ifstream in;
in.open(argv[1], ios::in);
while(!in.is_open())
{
char* name;
cout << "Invalid file name. Please enter file name: ";
cin >> name;
in.open(name, ios::in);
}
//variables
string line_bits, line_chars;
//reserve space up to constraints to reduce resizing time later
line_bits.reserve(150);
line_chars.reserve(1000);
int line = 0;
//loop over lines (<=50 by constraint, ignore the rest)
while((in >> line_bits >> line_chars) && (line < 50))
{
line++;
//impose bit and char constraints
if(line_bits.length() > 150 ||
line_chars.length() > 1000)
continue; //skip this line
(TransformLine(line_bits, line_bits.begin(), line_chars, line_chars.begin()) == true) ? (cout << "Yes\n") : (cout << "No\n");
}
//close file
in.close();
return 0;
}
bool TransformLine(const string & bits, str_it bits_front, const string & chars, str_it chars_front)
{
//using iterators so store current length as local const
//can make these const because they're not altered here
int bits_length = distance(bits_front, bits.end());
int chars_length = distance(chars_front, chars.end());
//check success rule
if(bits_length == 0 && chars_length == 0)
return true;
//Check fail rules:
//1. next bit is 0 but next char is B
//2. bits length is zero (but char is not, by previous if)
//3. char length is zero (but bits length is not, by previous if)
if((*bits_front == '0' && *chars_front == 'B') ||
bits_length == 0 ||
chars_length == 0)
return false;
//we now know that chars_length != 0 => chars_front != chars.end()
//kill a bit and then call recursively with each possible reduction of front char group
bits_length = distance(++bits_front, bits.end());
//current char group tracker
const char curr_char_type = *chars_front; //use const so compiler can optimize
int curr_pos = distance(chars.begin(), chars_front); //position of current front in char string
//since chars are 0-indexed, the following is also length of current char group
//start searching from curr_pos and length is relative to curr_pos so subtract it!!!
int curr_group_length = chars.find_first_not_of(curr_char_type, curr_pos)-curr_pos;
//make sure this isn't the last group!
if(curr_group_length < 0 || curr_group_length > chars_length)
curr_group_length = chars_length; //distance to end is precisely distance(chars_front, chars.end()) = chars_length
//kill the curr_char_group
//if curr_group_length = char_length then this will make chars_front = chars.end()
//and this will mean that chars_length will be 0 on next recurssive call.
chars_front += curr_group_length;
curr_pos = distance(chars.begin(), chars_front);
//call recursively, adding back a char from the current group until 1 less than starting point
int added_back = 0;
while(added_back < curr_group_length)
{
if(TransformLine(bits, bits_front, chars, chars_front))
return true;
//insert back one char from the current group
else
{
added_back++;
chars_front--; //represents adding back one character from the group
}
}
//if here then all recursive checks failed so initial must fail
return false;
}
They give the following test cases, which my code solves correctly:
Sample input:
1| 1010 AAAAABBBBAAAA
2| 00 AAAAAA
3| 01001110 AAAABAAABBBBBBAAAAAAA
4| 1100110 BBAABABBA
Correct output:
1| Yes
2| Yes
3| Yes
4| No
Since a transformation is possible if and only if copies of it are, I tried just copying each binary and letter sequences onto itself various times and seeing how the clock goes. Even for very long bit and character strings and many lines it has finished in under 10 seconds.
My question is: since CodeEval is still saying it is running longer than 10 seconds but they don't share their input, does anyone have any further suggestions to improve the performance of this recursion? Or maybe a totally different approach?
Thank you in advance for your help!
Here's what I found:
Pass by constant reference
Strings and other large data structures should be passed by constant reference.
This allows the compiler to pass a pointer to the original object, rather than making a copy of the data structure.
Call functions once, save result
You are calling bits.length() twice. You should call it once and save the result in a constant variable. This allows you to check the status again without calling the function.
Function calls are expensive for time critical programs.
Use constant variables
If you are not going to modify a variable after assignment, use the const in the declaration:
const char curr_char_type = chars[0];
The const allows compilers to perform higher order optimization and provides safety checks.
Change data structures
Since you are perform inserts maybe in the middle of a string, you should use a different data structure for the characters. The std::string data type may need to reallocate after an insertion AND move the letters further down. Insertion is faster with a std::list<char> because a linked list only swaps pointers. There may be a trade off because a linked list needs to dynamically allocate memory for each character.
Reserve space in your strings
When you create the destination strings, you should use a constructor that preallocates or reserves room for the largest size string. This will prevent the std::string from reallocating. Reallocations are expensive.
Don't erase
Do you really need to erase characters in the string?
By using starting and ending indices, you overwrite existing letters without have to erase the entire string.
Partial erasures are expensive. Complete erasures are not.
For more assistance, post to Code Review at StackExchange.
This is a classic recursion problem. However, a naive implementation of the recursion would lead to an exponential number of re-evaluations of a previously computed function value. Using a simpler example for illustration, compare the runtime of the following two functions for a reasonably large N. Lets not worry about the int overflowing.
int RecursiveFib(int N)
{
if(N<=1)
return 1;
return RecursiveFib(N-1) + RecursiveFib(N-2);
}
int IterativeFib(int N)
{
if(N<=1)
return 1;
int a_0 = 1, a_1 = 1;
for(int i=2;i<=N;i++)
{
int temp = a_1;
a_1 += a_0;
a_0 = temp;
}
return a_1;
}
You would need to follow a similar approach here. There are two common ways of approaching the problem - dynamic programming and memoization. Memoization is the easiest way of modifying your approach. Below is a memoized fibonacci implementation to illustrate how your implementation can be speeded up.
int MemoFib(int N)
{
static vector<int> memo(N, -1);
if(N<=1)
return 1;
int& res = memo[N];
if(res!=-1)
return res;
return res = MemoFib(N-1) + MemoFib(N-2);
}
Your failure message is "Aborted after 10 seconds" -- implying that the program was working fine as far as it went, but it took too long. This is understandable, given that your recursive program takes exponentially more time for longer input strings -- it works fine for the short (2-8 digit) strings, but will take a huge amount of time for 100+ digit strings (which the test allows for). To see how your running time goes up, you should construct yourself some longer test inputs and see how long they take to run. Try things like
0000000011111111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAA
00000000111111110000000011111111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAA
and longer. You need to be able to handle up to 150 digits and 1000 letters.
At CodeEval, you can submit a "solution" that just outputs what the input is, and do that to gather their test set. They may have variations so you may wish to submit it a few times to gather more samples. Some of them are too difficult to solve manually though... the ones you can solve manually will also run very quickly at CodeEval too, even with inefficient solutions, so there's that to consider.
Anyway, I did this same problem at CodeEval (using VB of all things), and my solution recursively looked for the "next index" of both A and B depending on what the "current" index is for where I was in a translation (after checking stoppage conditions first thing in the recursive method). I did not use memoization but that might've helped speed it up even more.
PS, I have not run your code, but it does seem curious that the recursive method contains a while loop within which the recursive method is called... since it's already recursive and should therefore encompass every scenario, is that while() loop necessary?

Debug Assertion Failed! String manipulation using pointer arithmetic

EDIT: Pastebin links to the entirety of the code at the bottom
for my CS215 course, I was given a class called String215 which is a basic string class to help in the understanding of dynamic memory allocation and pointer arithmetic with char arrays.
The class was given to me in a very basic skeleton form with prototypes but no implementations, along with a test function to test my implementations. I CAN NOT use any C String functions in this assignment.
The part of the program which is troubling is the append function, which just appends a parameter string215 object to the end of the current string215 object.
// Add a suffix to the end of this string. Allocates and frees memory.
void string215::append(const string215 &suffix)
{
char *output = new char[str_len(data)+suffix.length()+1];
for(int x = 0; x < str_len(data); x++) {
*output = *data;
output++;
data++;
}
for(int x = 0; x < suffix.length(); x++) {
*output = suffix.getchar(x);
output++;
}
*output = '\0';
output -= (str_len(data)+suffix.length()+1);
delete[] data;
data = output;
}
This portion of the code is tested in the 13th test of the test function as shown here:
string215 str("testing");
...
// Test 13: test that append works in a simple case.
curr_test++;
string215 suffix("123");
str.append(suffix);
if (strcmp(str.c_str(), "testing123") != 0) {
cerr << "Test " << curr_test << " failed." << endl;
failed++;
}
Here is the description of the append class:
Add the suffix to the end of this string. Allocates a new, larger, array; copies the old contents, followed by the suffix, to the new array; then frees the old array and updates the pointer to the new one.
My program aborts at the very end of the append function execution with the error message:
Debug Assertion Failed!
Program: [Source path]\dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
...
Abort || Retry || Ignore
I'm fairly certain it has something to do with my very poor memory management. I know it's not a lot to go on, but I've been struggling with this for hours on end and can't seem to figure it out.
Here's a pastebin of the .cpp and .h file for this program
string215.cpp: http://pastebin.com/Xh2SvDKJ
string215.h: http://pastebin.com/JfAJDEVN
Any help at all is greatly appreciated!
Thanks,
RAW-BERRY
You are changing data pointer before delete[]. You need to delete[] exactly the same value you got from new[].
Also, you are incrementing output pointer str_len(data)+suffix.length() times, and you take it back by str_len(data) + suffix.length() + 1.
I would use separate variables for iteration to solve these problems.
You increment output exactly str_len(data) + suffix.length() times. Note that you don't increment output after *output = '\0';.
So to go back to the start, you should use:
output -= (str_len(data) + suffix.length());
By the way, some of the code is not very efficient. For example, getchar uses a loop instead of simply returning data[index]. You use getchar in append, which means that the performance isn't great.
EDIT: As zch says, you use delete[] data after modifying data, but note that even before that you use str_len(data) after modifying data (when deciding how many bytes to go skip back), so the calculation is wrong (and my suggestion above is also wrong, because str_len(data) is now zero).
So I think your problem is with the line
for(int x = 0; x < str_len(data); x++) {
Notice that the size of 'data' is changing at each iteration of the loop. As you increment 'x', you are decreasing the length of 'data'. Suppose 'data' is a string holding "hello": in the first iteration of the loop x=0 and str_len(data)=5; in the second iteration x=1 and str_len(data)=4. Thus the for loop executes half as many times as you need it to and 'data' does not end up pointing to the end of the data string

length of sub-sequence in the string

I need to implement lastSeq function,which gets as argument string str and char chr
and returns the length of last sequence of repeated chr (the sequence can be of any length)
for example:
lastSeq("abbaabbbbacd",'a') should return 1
lastSeq("abbaabbbbacd",'b') should return 4
lastSeq("abbaabbbbacd",'t') should return 0
Is there C++ function which can solve it?
This appear to be homework, so I'm just going to give you direction so that you can find the answer by yourself.
First, how would you do it yourself, without a computer to give the correct result for your samples. From those manual run, how would you generalize then in simple steps so that you can solve the problem for all different inputs.
By this point you should have a rough algorithm to solve the problem. What do you know about storage of string in C++, and the method that are available from that class? Can some one them be used to solve some of the steps of your algorithm?
Try to write a program using those function, to compile it and to run it. Do you get the expected result? If not, can you try to print intermediate state (using std::cout << "Some value: " << variable << "\n";) to try to debug it.
Once you have done all of that, and if you are still having issues, update your question with your code, and we'll be able to give you more directed help.
int lastSeq(char *str, char chr)
{
int i = strlen(str);
int l = 0;
while(--i>=0)
if(*(str + i) == chr && ++l)
break;
while(--i>=0 && chr == *(str + i) && ++l);
return l;
}