• Advertisement
Sign in to follow this  

[C++] figuring out the char

This topic is 3842 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Sorry if this is such a lame question, but I need help in getting this thing right. I've looked through countless resources, but none so far have granted to my favor. I am working on a console version of an accounting program, specifically the basic password protection part. This module divides into the following categories: - main.cpp - Password.cpp - Password.h The problem I have is narrowed down to the following functions: Password.h/.cpp functions: - char password[20]; - int SetPass(); - int GetPass(char *arg1); My ultimate question and fustration is in trying to get the program to print the password on the console screen. When compiled and executed, all that is printed out is the first character of "google" (hence 'g'). I know I must be doing something wrong, I just do not know what exactly. If anyone may have the slightest idea as to this, help would be greatly appreciated. Thanks. PS: For those inquiring why I do not use another variable type such as STRING, the success of my Password module depends on the specific use of char. Password.h:
#include <stdio.h>

class Password {
private:
	char password[20];
	char *ptr; // not important
	int GETCH(void); // not important
public:
	int BreakPass(); // not important
	int SetPass(char *arg1);
	char GetPass();
};

Password.cpp function definitions:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include "Password.h"

/*
Other function definitions omitted
*/
int Password::SetPass(char *arg1) {
	strcpy_s(password, arg1); //copies arg. input to password variable
	return 0;
}

char Password::GetPass() {
	return *password; //returns password
}

main.cpp
#include <stdio.h>
#include <iostream>
#include <string.h>
#include "Password.h"

using namespace std;

int main()
{
	Password pwd;

	pwd.SetPass("google");
	cout << pwd.GetPass(); // prints password to user

	return 0;
}

Share this post


Link to post
Share on other sites
Advertisement
Use std::string, and you won't have to deal with these things. :-)

EDIT: Sorry, forgot to actually answer.

Your function is only returning a single character. Its return type should be char* rather than char, and you chould return password, not *password.

*password dereferences the pointer and just gives you the actual character at that address.

Share this post


Link to post
Share on other sites
You return single character:
char Password::GetPass() {
return *password; //returns password
}

THUGSTOOLS

[suorce]char *Password::GetPass() {
return password; //returns password
}
[/source]Is what returns the string.

Of course, C with classes isn't really useful. std::string would take care of any such problems.

Share this post


Link to post
Share on other sites
Thanks, I never knew to use char* instead of char, I guess now I do. Thanks for the quick responses/help :)!

Share this post


Link to post
Share on other sites
#include <stdio.h>
#include <string>

class Password
{
private:
std::string password;
public:
void SetPass(std::string pass)
{
password = pass;
}

std::string GetPass()
{
return password;
}
};

Share this post


Link to post
Share on other sites
Quote:
Original post by vrok137
Thanks, I never knew to use char* instead of char, I guess now I do. Thanks for the quick responses/help :)!


That's not what you were told though. Use std::string instead of char*. [wink]

char* is for C programs, you claim to be using C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spoonbender
That's not what you were told though. Use std::string instead of char*. [wink]

char* is for C programs, you claim to be using C++.


I would use std::string, but my BreakPass() method (which basically conceals the password as its being typed) requires the variable type char. Unless there is a way to convert between std::string and char effectively i'm open for ideas.

BTW here is the BreakPass() function definition:

int Password::GETCH(void) {
return _getch(); // does not echo input
}

int Password::BreakPass() { //uses global var. password and ptr
char input;
int count;

count = 0;

printf("enter your password: ");

do
{

input = GETCH();
if(input == '\xD') break; // enter pressed?
putc('*', stdout);
ptr = &input;
password[count] = *ptr;
count++;

}while(count < 20);

password[count++] = '\0'; // terminate the string

printf("\nyour password: %s\n", password);

return 0;
}

Share this post


Link to post
Share on other sites

int Password::BreakPass() {
//assumes password is declared std::string password
//also uses std::cin for input and std::cout for output

char input;
int count;

count = 0;

std::cout << "Please enter password: ";

do
{
std::cin >> input;
if(input == '\xD') break; // enter pressed?
std::cout << '*';
password[count] = input;
++count;
}while(count < 20);


Now someone will rearrange my (your) loop, but that's a C++ version of what you're trying to do.

Share this post


Link to post
Share on other sites
You can still use Alpha_ProgDes's code with your getch function:


// don't return an int
// since you always return 0, its kind of pointless
void Password::BreakPass() {
// assume we no longer care about how long the password is
// yay std::string!
// if you need to call this function multiple times
// you can empty the old password thusly:
// password.clear();

std::cout << "Please enter password: ";

char input;
while( (input = _getch()) != '\xD' )
{
std::cout << '*';
password.push_back(input);
}
std::cout << "\nYou password is: " << password << '\n';
}



In case you havent come across a loop with a condition like that,
(input = _getch()) != '\xD'
means
"assign input to _getch(). Then evaluate (assigned_value != '\xD')".

Share this post


Link to post
Share on other sites
Thanks everyone for all your help and advice. Because of so, I was able to use char* in making my password module. Good news is that its finally complete and running! Here is the source code (compiled and ready to execute) if any of you are interested in how I did it:

Thanks again for all your help [smile]


#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <string.h>

using namespace std;

class Password {
private:
char* password;
public:
Password();
Password(char* arg1);
void SetPass(char* arg1);
char* GetPass();
int BreakPass();
};

Password::Password() {
SetPass("password");
}

Password::Password(char* arg1){
SetPass(arg1);
}

void Password::SetPass(char* arg1) {
password = arg1;
}

char* Password::GetPass() {
return password;
}

int Password::BreakPass() {

char *ptr;

char input;
char temp_pass01[11];
char *temp_pass02;

int count;

count = 0;

std::cout << "Please enter password: ";

do {
input = _getch();
if(input == '\xD') break;
cout << "*";

ptr = &input;
temp_pass01[count] = *ptr;

count ++;
} while (count < 10);

temp_pass01[count++] = '\0'; //converts char to char*
temp_pass02 = temp_pass01;

return strcmp(password, temp_pass02);// returns 0 if a perfect match
}

int main() {
Password pwd; // the default pass is "password"
int verify = 1;

verify = pwd.BreakPass();

if (verify == 0) cout << "\n\nAccess Granted...\n\n";
else cout << "\n\nAccess Denied\n\n";

return 0;
}

Share this post


Link to post
Share on other sites
when you need to get a char* from a string call string's c_str() member function

Share this post


Link to post
Share on other sites
Way to ignore all the useful advice you were given...

You code will break in the future. Using char pointers to represent strings simply isn't smart. Your code will contain memory leaks.

Look at my breakpass function compared to yours. Can you not see the difference in the number of lines? Each line you write is one that could contain a logic error. Each line is one that will need to be maintained. You code contains redundant pointer assignments that don't need to be there. But I'm not going to point these out to you, I doubt you'll listen. Anyway, given that a superior implementation has already been posted there is no point.


Enjoy your bugs, for they will be many while you use nul terminated byte arrays to represent text in your code... [sad]

Share this post


Link to post
Share on other sites
Bleh.


// The header order is inconsistent. The general approach is to include:
// - Standard headers first (in this case, "iostream")
// - Platform-specific headers second (in this case, "conio.h")
// - Third-pary headers last (in this case, "stdio.h", "string.h")
// Also, you are providing the C-language headers "stdio.h" and "string.h"
// yourself, which represents more work potentiallly than using the standard
// versions "cstdio" and "cstring".
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <string.h>

using namespace std;

class Password {
private:
char* password;
public:
Password();

// Usability problem: this constructor may not be safely used
// from a temporary string, (such as a string literal) because
// its argument is non-constant. Ownership of pointer is not
// documented, so idiomatic C++ suggests that the caller conserves
// the ownership of the pointer and may delete or destroy it
// at will.
Password(char* arg1);

// Same usability and ownership problems as the above.
void SetPass(char* arg1);

// Ownership of pointer is not documented. Idiomatic C++ suggests
// that the pointer is a temporary copy of the contents of the
// password, which remains alive until the end of the statement in
// which the function is called.
char* GetPass();

// Undocumented return value. What does the integer represent.
int BreakPass();
};

// This code is inconsistent and wrong, it breaks obvious and idiomatic
// code such as the following:
// Password pass;
// pass.GetPass()[0] = '\0';
// This code is only allowed if the pointers are all 'const char*'
// but not if pointers are non-const.
Password::Password() {
SetPass("password");
}

// Ownership problem: the class interface did not specify that the pointer
// should remain valid after the call has been performed. Because of this,
// idiomatic code such as the following will break:
// char pass[] = "password";
// return Password(pass);
Password::Password(char* arg1){
SetPass(arg1);
}

// Same ownership problem as above.
void Password::SetPass(char* arg1) {
password = arg1;
}

// Exposes the internal state of the class. This makes the class absolutely
// useless, because it no longer provides any encapsulation whatsoever.
// Everything the class does could be reduced to a standalone "BreakPass"
// function, using a class provides no benefit, but creates potential ownership
// issues and requires more code.
char* Password::GetPass() {
return password;
}

int Password::BreakPass() {

char *ptr;

char input;
char temp_pass01[11];
char *temp_pass02;

int count;

count = 0;

std::cout << "Please enter password: ";

do {
input = _getch();
if(input == '\xD') break;
cout << "*";

ptr = &input;
temp_pass01[count] = *ptr;

count ++;
} while (count < 10);

temp_pass01[count++] = '\0'; //converts char to char*
temp_pass02 = temp_pass01;

// This interface is _beyond_ silly. Breaking a password
// should be a true/false issue, not a 'return integer, which
// will be 0 if the password is broken' one.

return strcmp(password, temp_pass02);// returns 0 if a perfect match
}

int main() {
Password pwd; // the default pass is "password"

// This is silly: you initialize a variable
// with a meaningless value that gets overwritten
// on the next line, instead of initializing it with
// the correct value.
int verify = 1;

verify = pwd.BreakPass();

if (verify == 0) cout << "\n\nAccess Granted...\n\n";
else cout << "\n\nAccess Denied\n\n";

// This is non-idiomatic in C++
return 0;
}





Equivalent code (typing errors notwithstanding), but with:
  • Better abstraction.
  • Less bugs, counter-intuitive twists, and unsafe parts.
  • A more object-oriented design.
  • Better separation of responsibility.
  • Faster to develop and extend.



#include <string>
#include <iostream>
#include <conio.h>

// Definition of the Password object
typedef std::string Password;

// Definition of the password-break function
bool BreakPassword(const Password & target)
{
std::string attempt;
std::cout << "Please enter password: ";

char input;
while ((input = _getch()) != '\xD')
{
std::cout << "*";
attempt.push_back(input);
}

return attempt == target;
}

// Main function, tests the above
int main()
{
Password pass = "password";

if (BreakPassword(pass))
std::cout << "Access granted\n";
else
std::cout << "Access denied\n";
}




Share this post


Link to post
Share on other sites
Thank you for your <honest> advice. Despite have the word "idiomatic" burned into my retinas, I am currently in the process of further optimizing my code.

Thanks for the recomendations on using std::string instead. I am right now working on a way to set a consistent standard concerning the replacement of char* strings with std::string. Grant may be that this may take a day or two (since this Password module is only a part of the bigger jigsaw), but I will prevail [wink].

Thanks again for all your assistance guys.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement