How to pass an element of an array to an other? - c++

I am trying to take a new plate for a car and change the old one. I need the three letters to be capitals. The thing is that I cannot pass the "capital" element of newPlate array to the new_Plate array. The program compiles but the answer is soometimes %^&#%#$ and some other times nothing. I know I have a problem in the pointers.
void Car::set(char *newBrand, char *newPlate)
{
char new_Brand[80];
char new_Plate[8];
if(strlen(newPlate)==8)
{
for(int i=0;i<3;i++)
{
if(65<=(int)newPlate[i]<=90)
{
new_Plate[i]=newPlate[i]; // probably the problem
}
if(97<=(int)newPlate[i]<=122)
{
new_Plate[i]=(newPlate[i]+32); // probably the problem
}
cout<<new_Plate;
}
}
}

Your new_Plate string does not include a zero terminator.
Furthermore, 65<=(int)newPlate[i]<=90) is not valid in C++. You should write something like
'A'<=newPlate[i] && newPlate[i]<='Z')

The problem with the expression 65<=(int)newPlate[i]<=90 (aside from being unreadable, use more white spaces to make it more readable) is that it means ((65 <= (int) newPlate[i])) <= 90 which is not what it mathematically appears to mean.
This expression will ALWAYS be true because 65 <= (int) newPlate[i] will evaluate to either 1 or 0 and it is of course always < 90.
Also, to make the code even more readable use 'A' instead of 65 and the equivalent for any other character. Most programmers know that 'A' is 65 in ascii but you make them stop one or two seconds to realize that you really mean 'A'!
Also, you must terminate c-strings with a '\0' so you need one extra character at the end or, cout << new_Plate will invoke undefined behavior.
To print c strings the library will output characters from the input buffer until it finds the '\0', since it's not present in your buffer there is no predictable way to print it.
Check this, do you understand the changes?
#include <iostream>
#include <cstring>
using namespace std;
class Car {
public:
Car();
void set(const char *const newBrand, const char *const newPlate);
};
Car::Car()
{
}
void
Car::set(const char *const newBrand, const char *const newPlate)
{
char new_Brand[80];
char new_Plate[9];
size_t length;
size_t i;
(void) new_Brand;
length = strlen(newPlate);
for (i = 0 ; ((i < length) && (i < sizeof(new_Plate) - 1)) ; ++i) {
if (('A' <= newPlate[i]) && (newPlate[i] <= 'Z')) {
new_Plate[i] = newPlate[i];
} else if (('a' <= newPlate[i]) && (newPlate[i] <= 'z')) {
new_Plate[i] = (newPlate[i] - 32);
}
}
new_Plate[i] = '\0';
cout << '*' << new_Plate << '*' << endl;
}
int
main(void)
{
Car car;
car.set("audi", "example text");
return 0;
}

Related

Is this a usable solution for a `strcmp` substitute in C code?

I have made a <stdio.h> only strcmp equivalent... "ish"
But i WOULD like to know. Is there something i've skipped and/or should fix, if i decide to use this as a substitute for strcmp?
DISCLAIMER:: I have no intend to actually substitute strcmp from my daily usage, but I would like to know if I'm currently able to create a similar substitute for it.
code for it:
#include <stdio.h>
// #include <ctype.h> // Optional
typedef char string[20];
int stringcmp(string str1, string str2);
int strcount(string str);
int main (void)
{
string cmp1, cmp2;
printf("cmp1: ");
scanf("%s", cmp1);
printf("cmp2: ");
scanf("%s", cmp2);
// If you want the function to be ran Case-Insensitive, [ctype] library might be your friend
int result = stringcmp(cmp1, cmp2);
printf("(%i)\n", result);
return result;
}
int strcount(string str)
{
int i = 0;
while(str[i] != '\0')
{
i++;
}
return i;
}
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
}
return 0;
}
the function in topic makes usage of another one, by the way. Is that a problem in any way?
For starters the function declaration is incorrect.
In fact your function declaration after adjusting the parameters by the compiler looks like
int stringcmp( char *str1, char *str2);
while the declaration of the standard function strcmp looks like
int strcmp(const char *str1, const char *str2);
That is the function deals with pointers to constant strings because within the function passed strings are not changed.
To compare two strings there is no any need to calculate their lengths. It is just inefficient. Moreover you shall use the type size_t instead of the type int to store a length of a string because an object of the type int can be not large enough to store values of lengths of strings.
Also there is an explicit bug in your approach
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
because you are returning a positive value ( 1 ) when the first string is less than the second string while the standard C function strcmp returns a negative value in this case. and vice versa when the first string is greater than the second string you are returning again a positive value ( 2 ).
From the C Standard (7.23.4.2 The strcmp function)
3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by s1 is
greater than, equal to, or less than the string pointed to by s2.
And moreover the elements of strings shall be compared as objects of the type unsigned char.
Consider the following demonstrative program.
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char s1[] = { CHAR_MIN, '\0' };
char s2[] = { CHAR_MAX, '\0' };
printf( "s1 is greater than s2 is %s\n", 0 < strcmp( s1, s2 ) ? "true" : "false" );
return 0;
}
Its output is
s1 is greater than s2 is true
In fact the arrays are declared like
char s1[] = { -128, '\0' };
char s2[] = { 127, '\0' };
provided that the type char behaves as the type signed char (that is usually the default behavior of the type char for many compilers).
So if the elements of the arrays will be compared as objects of the type char then you will get an opposite result to the result of the standard C function strcmp.
The function can be much simpler defined for example the following way
int stringcmp( const char *str1, const char *str2 )
{
while ( *str1 && *str1 == *str2 )
{
++str1;
++str2;
}
return ( unsigned char )*str1 - ( unsigned char )*str2;
}
As you can see there is no any need to calculate preliminary lengths of the strings.
It seems like it would work, although strcmp does not return 0, 1, and 2, but 0, <0, and >0.
See https://www.cplusplus.com/reference/cstring/strcmp/ for reference.
By the way, why not use string.c_str()?
strcmp(string str1,string str2) will:
return an a number less than zero if str1 < str2
return zero if str1 == str2
return an a number more than zero if str1 > str2
so your function should imitate this behavior
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] == 0 && str2[i] == 0) return 0;
if (str1[i] == 0) return 1;
if (str2[i] == 0) return -1;
if (str1[i] < str2[i])
{
return -1;
}
else if (str1[i] > str2[i])
{
return 1;
}
}
return 0;
}
#include<stdio.h>
#include<string.h>
int main(){
printf("%d",strcmp("hell ","hell"));
}
bro scanf dosent scan white spaces but if you run the above code white spaces play an important role it prints 1;
so check alternative

strncat function c++ not working

I need to write void strncat which appends the first num characters of source to destination, plus a terminating null-character. If the length of the C string in source is less than num, only the content up to the terminating null-character is copied. What am i doing wrong?
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
const int MAXDESTINATION = 40;
const int MAXSOURCE = 150;
int main() {
char dest[MAXDESTINATION + 1] = "It don't mean a thing";
char src[MAXSOURCE + 1] = " if it don't got the Go-Go swing!";
int a = strlen(dest);
int b = strlen(src);
strncat(dest, src, MAXDESTINATION - a) ;}
void strncat(char destination[], const char source[], int num) {
if (int strlen(source) < num) {
int begin = 0;
bool less = false;
for (int i = 0; i <num; i++) {
if (destination[i] == '\0') {
begin = i;
less = true;
}
if (less == true) {
destination[begin] = source[i];
}
}
}
I'm guessing (since you haven't provided even the full definition of strncat) your problem is that you're not incrementing begin. The way it's written right now, the same spot is overwritten each time with the value at source[i]
You maybe want to say
destination[begin++] = source[i];
or maybe you should just use i instead, as begin should probably track i exactly, as it's initialized to i and then should be incremented once every time i is.
Also, from an efficiency standpoint, you're iterating over source multiple times. Once with your call to strlen (which has to go through each letter in the string to count them) and then again in your for loop. You should look to remove the strlen.
Compile errors:
error C1075 :end of file found before the left brace '{' ...
error c4996: 'strncat': this function or variable may be unsafe. consider using strncat_s instead.

Caesar Cipher C++ (using char pointer and shift as arguments)

I'm looking to make a method like so (which encrypts a message using Caesar Cipher, entered by the user and displays it):
void encrypt(char *message, int shift);
My code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <string.h>
char num(char c)
{
const char upper_alph[26] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
const char lower_alph[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
if(isupper(c)) {
for(int i = 0; i < 26; i++)
if(upper_alph[i] == c)
return i;
} else {
for(int i = 0; i < 26; i++)
if(lower_alph[i] == c)
return i;
}
return 0;
}
void encrypt(char *message, int shift)
{
int i = 0;
const char upper_alph[26] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
const char lower_alph[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
while(message[i] != NULL)
{
if(isalpha(message[i]))
{
if(isupper(message[i])) {
printf("%c", upper_alph[(num(message[i])+shift)%26]);
} else {
printf("%c", lower_alph[(num(message[i])+shift)%26]);
}
} else {
printf("%c", message[i]);
}
i++;
}
}
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
int main()
{
//reverse();
//printf("\n\n");
int rc;
char mes[1024];
int sh = 0;
rc = getLine ("Enter message to be encrypted: ", mes, sizeof(mes));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", mes);
return 1;
}
encrypt(mes, 1);
fflush(stdin);
getchar();
return 0;
}
Thank you to anyone who helps or tries to help.
:)
EDIT: Made many corrections. Still not working :/
EDIT2: Made a lot more corrections. Getting an access violation # "while(*message != '\0')"
EDIT3: Updated the code above to the working code. Thank you everyone for your help!
One problem is you never wrap-around. Consider if you are passed something like 'Z' or 'z' with any positive shift, then you will just increment outside of the array.
You need to do something like:
upper_alph[(num(message[i])+shift)%26]
and
lower_alph[(num(message[i])+shift)%26]
You also need to allocate memory for mes:
char mes[1024];
I believe your scanf is also incorrect (c is a character, s is a string):
scanf("%s", mes);
Using %s will however only read until it gets white-space, a better option may be to read the entire line with getline().
You'll get an "index out of bounds" error on these lines:
if(isupper(message[i])) {
printf("%c", upper_alph[num(message[i])+shift]);
} else {
printf("%c", lower_alph[num(message[i])+shift]);
}
You need to calculate the index in advance and make sure it is between 0 and 25:
int shiftedIndex = (num(message[i]) + shift) % 26;
You are aware of the fact that your code only works with English as input language?
It doesn't work because you didn't allocate memory for mes:
char mes[512]; // Enough space!
Use std::string is easier:
string mes;
int sh = 0;
cout << "Enter message to be encrypted: " << endl;
getline(cin, mes);
cout << "Enter a shift amount (1-25): " << endl;
cin >> sh;
encrypt(mes, sh);
And change encrypt function to:
void encrypt(const string &message, int shift)
And keep your characters in range:
upper_alph[(num(message[i])+shift)%26]
lower_alph[(num(message[i])+shift)%26]
There is a fundamental problem here that the OP isn't understanding. And that is, to the computer, letters are just numbers. It us us humans that assign meaning to those numbers, and we can't even decide on which numbers mean what (see comments on question re ASCII, EBDIC and Unicode).
Here is a table showing how the ASCII standard maps the numbers to letters.
Notice that the character 'a' is 97, 'b' is 98, 'c' is 99 and so on. The uppercase characters start at 65 and go up from there. Note also that the letter 'a' and 'A' are on the same row! This means the bit patterns of the lower 5 bits for an upper case letter and a lower case letter are the same. Finally, as the computer only ever sees characters as numbers, it can do numeric operations on them:-
'd' - 'a' == 3
100 - 97
The second thing to note is that mathematically the Caeser cipher is just an addition with a modulo:-
encoded character = (plain text character + shift) mod 26
So now the code can written much more efficiently:-
void Encode (char *message, int shift)
{
while (*message)
{
char c = *message;
if (isalpha (c)) // check c is a letter
{
// get the letter index: this maps 'A' to 0, 'B' to 1, etc
// it also maps 'a' to 32 (97 - 65), 'b' to 33, etc
c -= 'A';
// this is 32 for lower case characters and 0 for upper case
char case_of_c = c & 32;
// map 'a' to 'A', 'b' to 'B'
c &= 31;
// the caeser shift!
c = (c + shift) % 26;
// restore the case of the letter
c |= case_of_c;
// remap the character back into the ASCII value
c += 'A';
// save the result of the shift
*message = c;
}
++message;
}
}

I get a number 2 when I reverse my string

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

Nested for-loop solution

I made this program just out of interest and wanted to make it better. My problem is that I want to make a nested for-loop to carry out the iterations but I can't get my head around it, I have tried many times but my head is melting. Any help would be greatly appreciated. Also for some reason on windows and openSuse (from what I have seen) the program prints out some random characters after the expected output, a solution to this would be a great bonus. Thanks !
Sorry I didn't make it clearer, the point of the code is to be able to theoretically generate every combination of letters from AAAAAAAA to ZZZZZZZZ.
1) No it's not homework
#include <iostream>
using namespace std;
int main()
{
char pass [] = {'A','A','A','A','A','A','A','A'};
while(pass[0] != '[')
{
pass[7]++;
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
if(pass[6] == '[')
{
pass[6] = 'A';
pass[5]++;
}
if(pass[5] == '[')
{
pass[5] = 'A';
pass[4]++;
}
if(pass[4] == '[')
{
pass[4] = 'A';
pass[3]++;
}
if(pass[3] == '[')
{
pass[3] = 'A';
pass[2]++;
}
if(pass[2] == '[')
{
pass[2] = 'A';
pass[1]++;
}
if(pass[1] == '[')
{
pass[1] = 'A';
pass[0]++;
}
cout << pass << endl;
}
return 0;
}
Maybe like this:
const char char_first = 'A';
const char char_last = '[';
const unsigned int passlen = 8;
while (pass[0] != char_last)
{
++pass[passlen - 1];
for (unsigned int i = passlen - 1; i != 0; --i)
{
if (pass[i] == char_last)
{
++pass[i - 1]; // OK, i is always > 0
pass[i] = char_first;
}
}
}
For printing, include <string> and say:
std::cout << std::string(pass, passlen) << std::endl;
I took the liberty of making a few of the magic numbers into constants. If you're ever going to refactor this into a separate function, you'll see the merit of this.
Since (to output it) you use pass as a C string, it should be null terminated. Since it is not, garbage is printed. So you could define it as:
char pass [] = {'A','A','A','A','A','A','A','A','\0'};
or simpler
char pass[] = "AAAAAAAAA";
I'd forget about carrying on my own and just convert to/from numbers. What you're doing here is basically printing a numbers whose digits range from 'A' to ']', mappable to 0-28 via the magic of ASCII (why no ^ in passwords?)
Printing the number of anything then really boils down to
#include <iostream>
#include <cmath>
using namespace std;
std::string format(long num, int ndigits) {
if(ndigits == 0) {
return "";
} else {
char digit = 'A' + num % 28;
return format(num / 28, ndigits - 1) + digit;
}
}
int main()
{
for(int i = 0 ; i < powl(28,8) ; ++i) {
cout << format(i, 8) << endl;
}
}
You may still want to work in a char array instead of producing a billion temporary strings if you're serious about the loop, but the principle stays the same.
First try to find the common parts in the expressions looking like
if(pass[7]=='[')
{
pass[6]++;
pass[7] = 'A';
}
You should think along a line like "There's always the same number here, and a one-lower number there". Then, you replace that notion of a number with a variable and find out which range the variable has. KerrekSB gave you a solution, try to arrive at similar code from your own reasoning.
You just have to play a bit with your while and make it fit a for-loop.
while(pass[0] != '[') becomes for (i=0; pass[0] != '['; i++)
then you can replace all ifs with only one:
if(pass[i+1] == '[')
{
pass[i+1] = 'A';
pass[i]++;
}
How did we come to that conclusion? Well if you check all your if-statements all that changes between them is the indices. You can see clearly that pattern so you just replace the indices with a variable.
For starters, this is definitely not a case for a nested loop. In fact,
your entire code boils down to:
pass = initialPattern();
while ( isValidPattern( pass ) ) {
nextPattern( pass );
std::cout << pass << std::endl;
}
(But I wonder if you don't really mean to do the output before the
increment.)
Now all you have to do is define the type of pass and relevant
functions; you might even consider
putting everything in a class, since all of the functions operate on the
same data instance.
Judging from your code, pass should be an std::string with 8
characters; the initialization could be written:
std::string pass( 8, 'A' );
isValidPattern apparently only looks at the first character. (I'm not
sure that's correct, but that's what your code does.) Something like:
bool
isValidPattern( std::string const& pattern )
{
return pattern[0] != '[';
}
according to your code, but something like:
struct NotIsUpper
{
bool operator()( char ch ) const
{
return ! ::isupper( static_cast<unsigned char>( ch ) );
}
};
bool
isValidPattern( std::string const& pattern )
{
return pattern.size() == 8
&& std::find_if( pattern.begin(), pattern.end(), NotIsUpper() )
== pattern.end();
}
would seem more appropriate. (Of course, if you're doing any sort of
coding with text, you'd already have NotIsUpper and its siblings in
your tool kit.)
Finally, nextPattern seems to be nothing more than a multi-digit
increment, where the data is stored in big-endian order. So the
following (classical) algorithm would seem appropriate:
void
nextPattern( std::string& pattern )
{
static char const firstDigit = 'A';
static char const lastDigit = 'Z';
static std::string const invalidPattern( 1, '[' );
std::string::reverse_iterator current = pattern.rbegin();
std::string::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit ) {
*current = firstDigit;
++ current;
}
if ( current != end ) {
++ *current;
} else {
pattern = invalidPattern;
}
}
Formally, there is no guarantee in the standard that the letters will
be encoded in sequential ascending order, so for maximum portability,
you probably should in fact use an std::vector<int> with values in the
range [0, 26), and map those to letters just befor output. This
would be trivial if you put all of these operations in a class, since
the internal representation wouldn't be visible to the client code.
Something like:
class PatternGenerator
{
std::vector<int> myData;
public:
explicit PatternGenerator()
: myData( 8, 0 )
{
}
void next()
{
static int const lastDigit = 26;
std::vector<int>::reverse_iterator current = pattern.rbegin();
std::vector<int>::reverse_iterator end = pattern.rend();
while ( current != end && *current == lastDigit - 1 ) {
*current = 0;
++ current;
}
if ( current != end ) {
++ *current;
} else {
myData.front() = lastDigit;
}
}
bool isValid() const
{
return myData.front() < lastDigit;
}
friend std::ostream& operator<<(
std::ostream& dest, PatternGenerator const& obj )
{
static char const characterMap[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ( std::vector<int>::iterator current = obj.myData.current();
current != obj.myData.end():
++ current ) {
dest << characterMap[*current];
}
return dest;
}
};
(Note that things like isValid become simpler, because they can depend on the class invariants.)
Given this, all you have to write is:
int
main()
{
PatternGenerator pass;
while ( pass.isValid() ) {
std::cout << pass << std::endl;
pass.next();
}
return 0;
}
To do nested loops, you need to turn it inside-out.
You've written the code thinking as follows: go through all the possibilities for the last symbol, then change the second-last once and go back, etc. That's like counting up from 1, getting to 10 and putting a 1 in the tens column, etc.
Nested loops work the other way: go through the possibilities for the first symbol, allowing the inner loops to take care of possibilities for the other symbols each time. i.e., "list all those numbers, in order, that start with 0 in the millions place, then the ones that start with 1 etc.". In the outermost loop, you just set that value for the first digit, and the nested loops take care of the rest.