C++, String to Array of Characters with my professor's limitations


C++, String to Array of Characters with my professor's limitations



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.


std::string


strlen



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.


str



However, if I were to put something in quotes in the place of str, it accepts it just fine, despite them both being strings.


str



What am I doing wrong?





if you are not suppose to use the std::string class, why is the first parameter passed into the function a std::string object?
– theKidOfArcrania
Jul 3 at 6:51



std::string


std::string





also the sizeof operator does not determine the length of a string. Strings (c-strings) are null-terminated, i.e. the last element of a string is zero/null.
– theKidOfArcrania
Jul 3 at 6:53


sizeof





Well, you are actually going to use both (array and pointer). You will hold your string in an array of char and you will use a pointer (or two) to compare the first/last and (first+1)/(last-1) chars.
– David C. Rankin
Jul 3 at 7:13


char





You can't use std::string...**but can you use std::vector<char>** ;)
– JHBonarius
Jul 3 at 7:48



std::string


std::vector<char>





char arr = "str"; works because the array size is determined from the string literal at compile time, just like if you write int arr = {1,2,3};.
– molbdnilo
Jul 3 at 8:07


char arr = "str";


int arr = {1,2,3};




5 Answers
5



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. '' so you can end your loop when you encounter null character. For example:


''


int len = 0;
while ( str[len] != '' ) 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. :)


if



I'm sure you can put things together and revise your study material a bit to solve this.



Best of luck!
Happy coding!





Why the down vote?
– Azeem
Jul 3 at 7:29



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.


strlen



Let's do that:



First, you should have the prototype (no strings allowed, right?)


string


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


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];





Personally I think the 2 character case should always return true, but this is nicely set out, +1.
– Bathsheba
Jul 3 at 8:06


true





@Bathsheba before doing end -= 2, you could do if ((end - str) == 2) and return true to handle the 2-character case.
– Shadow2531
Jul 4 at 5:42


end -= 2


if ((end - str) == 2)



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).


const char*



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:


strlen


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:


l


l


false


l


true


l


l



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.


char arr = str;


sizeof



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.


strlen



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





That returns true for the string "teteth".
– Shadow2531
Jul 4 at 4:54





@Shadow2531 I request you to check once again by calling the function as haveTheSameTwoChars("teteth");
– paper.plane
Jul 4 at 6:09






Oops, sorry. You're all good.
– Shadow2531
Jul 4 at 6:43



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:


begmatchend


#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.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

PHP contact form sending but not receiving emails