I need the send and integer to a function and then append that to the end of a constant character.
int main (void)
{
append(1);
}
int append(int input)
{
const char P = 'P';
//This where I want to append 1 to P to create "P1"'
}
No matter what you do, you need to convert the number to a string, otherwise you can't create a string containing both numbers.
You can actually combine both the concatenation and the int-to-string conversion in one function call: sprintf:
char output[16];
sprintf(output, "P%d", input);
I'm not an expert on C, but I don't believe constants should be changed once they are defined.
Not sure if you can add something to a const chat (since its a const).
But why not:
char p[3];
sprintf(p, "P%d",input);
You cannot assign more than one character value to a char. For doing that you would have to take a string. Maybe like this.
int append(int input)
{
const char P = 'P';
//This where I want to append 1 to P to create "P1"
char app[2] ; //extend that for your no. of digits
app[0] = P '
app[1] = (char) input ;
}
This is for one digit. You can allocate dynamic memory for big integers and do the same in a loop.
What about using strncat?
See a working example on codepad: http://codepad.org/xdwhH0ss
I would convert the number to a string (assuming you have access to a function called itoa in this example and concatenate it to the character. If you don't have access to itoa you could sprintf instead.
itoa method:
#include <stdio.h>
#include <stdlib.h>
char *foo(const char ch, const int i)
{
char *num, *ret;
int c = i;
if(c <= 0) c++;
if(c == 0) c++;
while(c != 0)
{
c++;
c /= 10;
}
c += 1;
if(!(num = malloc(c)))
{
fputs("Memory allocation failed.", stderr);
exit(1);
}
if(!(ret = malloc(c + 1)))
{
fputs("Memory allocation failed.", stderr);
free(num);
exit(1);
}
itoa(i, num, 10);
ret[0] = ch;
ret[1] = 0x00;
strcat(ret, num);
free(num);
return ret;
}
int main(void)
{
char *result;
if(!(result = foo('C', 20))) exit(1);
puts(result);
free(result);
return 0;
}
sprintf method:
#include <stdio.h>
#include <stdlib.h>
char *foo(const char ch, const int i)
{
char *num, *ret;
int c = i;
if(c <= 0) c++;
if(c == 0) c++;
while(c != 0)
{
c++;
c /= 10;
}
c += 1;
if(!(num = malloc(c)))
{
fputs("Memory allocation failed.", stderr);
exit(1);
}
if(!(ret = malloc(c + 1)))
{
fputs("Memory allocation failed.", stderr);
free(num);
exit(1);
}
sprintf(num, "%d", i);
ret[0] = ch;
ret[1] = 0x00;
strcat(ret, num);
free(num);
return ret;
}
int main(void)
{
char *result;
if(!(result = foo('C', 20))) exit(1);
puts(result);
free(result);
return 0;
}
I compiled and tested both of these and they seem to work quite nicely. Good luck.
Related
If I have a string like the following:
char* exampleString = "test$$";
Let's say that getpid() returns 1587.
How can I replace the $$ in the string with the result of getpid() such that the result would be a string "test1587"?
Since "test$$" is immutable and a pointer to it should better be char const* instead of char* you'd have to copy it to an array where you then can replace "$$".
Possible solution:
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char const *input = "foo$$bar";
pid_t pid = 1234;
size_t format_length = strlen(input);
char *format = calloc(format_length + 2, 1);
if (!format) {
fputs("Couldn't allocate memory :(\n\n", stderr);
return EXIT_FAILURE;
}
// copy input to format replacing "$$" with "%ld" in the process
bool replacement_done = false;
for (size_t i = 0; i < format_length + replacement_done; ++i) {
if (!replacement_done && i + 1 < format_length &&
input[i] == '$' && input[i + 1] == '$')
{
format[ i] = '%'; // just
format[++i] = 'l'; // being
format[++i] = 'd'; // safe.
replacement_done = true;
continue;
}
format[i] = input[i - replacement_done];
}
if (!replacement_done) {
free(format);
fputs("Nothing to do :(\n\n", stderr);
return EXIT_FAILURE;
}
char *result = malloc(1);
if (!result) {
free(format);
fputs("Couldn't allocate memory :(\n\n", stderr);
return EXIT_FAILURE;
}
// there is no guesswork needed, snprintf() will tell the needed size
int bytes_needed = snprintf(result, 1, format, (long)getpid());
if (bytes_needed < 0) {
free(format);
free(result);
fputs("snprintf() failed :(\n\n", stderr);
return EXIT_FAILURE;
}
char *temp = realloc(result, ++bytes_needed);
if (!temp) {
free(format);
free(result);
fputs("Couldn't allocate memory :(\n\n", stderr);
return EXIT_FAILURE;
}
result = temp;
int written = snprintf(result, bytes_needed, format, (long)getpid()); // long should be big enough
if(written < 0 || written >= bytes_needed ) {
free(format);
free(result);
fputs("snprintf() failed :(\n\n", stderr);
return EXIT_FAILURE;
}
puts(result); // done.
free(format);
free(result);
}
You can't do a direct substitution because your string (character array) is not long enough to hold the pid, and of course, if declared as a string literal is also not mutable.
There are a couple of ways you could go with this, but here's a reasonably elegant one:
/* Modify the existing string to be a pattern string for snprintf */
int len = strlen(exampleString) - 1; /* Can you see why I might do this? */
char* formatString = strdup(exampleString); /* Because we can't modify a literal */
int newLen = len + 12; /* How about this? */
char *pidString = malloc(newLen);
int i;
for (i = 0; i < len; i++) {
if (formatString[i] == '$' && formatString[i+1] == '$') {
formatString[i] = '%';
formatString[i+1] = 'd';
break;
}
}
snprintf(pidString, newLen - 1, formatString, getpid());
Can you follow how this works?
How would you enhance this to fail gracefully if the exampleString does not contain $$ ?
I am having an interesting memory problem with a simple string manipulation. The problem itself isn't actually in the reading of the string but right before it when I am trying to call the string.
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(100) + 1);
fprintf(stderr," After: %s \n", token);
}
Whenever I run this, the string if truncated right after the char *newToken is malloc'd. So the printout of this results in
Before: Willy Wanka's Chochlate Factory
After: Will Wanka's Chochlate F!
Anyone have any clue what this is? I looked at other examples of malloc, but can't figure out how it is going wrong here.
EDIT: FULL CODE BELOW. Take note I am a college student who just began C, so it isn't perfect by anymeans. But it works up until this error.
Function calls goes as follows. Main->initialReadAVL (This part works perfectly)
Then after commandReadAVL is called which goes commandReadAVL->ReadHelper (Again works fine here.
Then CleanUpString->removeSpaces(works fine)
Then CleanUpString->removeInvalid(THIS IS WHERE IT ERRORS)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "node.h"
#include "avl.h"
#include "scanner.h"
#include "bst.h"
/* Options */
int avlSwitch = 0;
int bstSwitch = 0;
int insertSwitch = 0;
int deleteSwitch = 0;
int frequencySwitch = 0;
int displaySwitch = 0;
int statisticSwitch = 0;
int ProcessOptions(int argc, char **argv);
char *cleanUpString(char *token);
char *turnToLowerCase(char *token);
char *removeSpaces(char *token);
char *removeInvalid(char *token);
char *readHelper(FILE *in);
void Fatal(char *fmt, ...);
void preOrder(struct node *root);
void initialReadAVL(avl *mainAVL, FILE *in);
void initialReadBST(bst *mainBST, FILE *in);
void commandReadBST(bst *mainBST, FILE *commandList);
void commandReadAVL(avl *mainAVL, FILE *commandList);
int main(int argc, char **argv) {
struct avl *mainAVL;
struct bst *mainBST;
FILE *text;
FILE *commandList;
if(argc != 4){
Fatal("There must be 4 arguments of form 'trees -b corpus commands' \n");
}
int argIndex = ProcessOptions(argc,argv);
text = fopen(argv[2], "r");
commandList = fopen(argv[3], "r");
//Protect against an empty file.
if (text == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[2]);
exit(1);
}
if (commandList == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[3]);
exit(1);
}
if (avlSwitch){
mainAVL = newAVL();
initialReadAVL(mainAVL, text);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
commandReadAVL(mainAVL, commandList);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
}
else if (bstSwitch){
mainBST = newBST();
initialReadBST(mainBST, text);
preOrder(mainBST->root);
commandReadBST(mainBST, commandList);
preOrder(mainBST->root);
}
return 0;
}
void commandReadAVL(avl *mainAVL, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
fprintf(stderr,"%s \n", textSnip);
insertAVL(mainAVL, textSnip);
break;
case 'd':
deleteAVL(mainAVL, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
void commandReadBST(bst *mainBST, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
insertBST(mainBST, textSnip);
break;
case 'd':
deleteBST(mainBST, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
char *readHelper(FILE *in){
char *token;
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
void initialReadBST(bst *mainBST, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertBST(mainBST, token);
}
}
}
void initialReadAVL(avl *mainAVL, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertAVL(mainAVL, token);
}
}
}
//Helper Function to clean up a string using all the prerequisites.
char *cleanUpString(char *token){
char *output = malloc(sizeof(*token)+ 1);
if (token != NULL){
output = removeSpaces(token);
fprintf(stderr,"before : %s \n", output);
output = removeInvalid(output);
fprintf(stderr,"%s \n", output);
output = turnToLowerCase(output);
return output;
}
return NULL;
}
//Helper function to turn the given string into lower case letters
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
//Helper function to remove redundent spaces in a string.
char *removeSpaces(char *token){
char *output;
int x = 0;
int y = 0;
while (x < strlen(token)){
if (token[x]== ' ' && x < strlen(token)){
while(token[x] == ' '){
x++;
}
output[y] = ' ';
y++;
output[y] = token[x];
y++;
x++;
}
else {
output[y] = token[x];
y++;
x++;
}
}
return output;
}
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(* token)+ 1);
fprintf(stderr," After: %s \n", token);
int x = 0;
int y = 0;
while (x < strlen(token)){
if (!isalpha(token[x]) && token[x] != ' '){
x++;
}
else {
newToken[y] = token[x];
y++;
x++;
}
}
return newToken;
}
//Processes a system ending error.
void Fatal(char *fmt, ...) {
va_list ap;
fprintf(stderr,"An error occured: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(-1);
}
//Processes the options needed to be executed from the command line
int ProcessOptions(int argc, char **argv) {
int argIndex;
int argUsed;
int separateArg;
argIndex = 1;
while (argIndex < argc && *argv[argIndex] == '-')
{
/* check if stdin, represented by "-" is an argument */
/* if so, the end of options has been reached */
if (argv[argIndex][1] == '\0') return argIndex;
separateArg = 0;
argUsed = 0;
if (argv[argIndex][2] == '\0')
{
separateArg = 1;
}
switch (argv[argIndex][1])
{
case 'b':
bstSwitch = 1;
break;
case 'a':
avlSwitch = 1;
break;
default:
Fatal("option %s not understood\n",argv[argIndex]);
}
if (separateArg && argUsed)
++argIndex;
++argIndex;
}
return argIndex;
}
void preOrder(struct node *root) {
if(root != NULL)
{
fprintf(stderr,"%s ", root->key);
preOrder(root->lChild);
preOrder(root->rChild);
}
}
ReadString()
char *
readString(FILE *fp)
{
int ch,index;
char *buffer;
int size = 512;
/* advance to the double quote */
skipWhiteSpace(fp);
if (feof(fp)) return 0;
ch = fgetc(fp);
if (ch == EOF) return 0;
/* allocate the buffer */
buffer = allocateMsg(size,"readString");
if (ch != '\"')
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"first character was <%c>\n",ch);
exit(4);
}
/* toss the double quote, skip to the next character */
ch = fgetc(fp);
/* initialize the buffer index */
index = 0;
/* collect characters until the closing double quote */
while (ch != '\"')
{
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"no closing double quote\n");
exit(6);
}
if (index > size - 2)
{
++size;
buffer = reallocateMsg(buffer,size,"readString");
}
if (ch == '\\')
{
ch = fgetc(fp);
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"escaped character missing\n");
exit(6);
}
buffer[index] = convertEscapedChar(ch);
}
else
buffer[index] = ch;
++index;
ch = fgetc(fp);
}
buffer[index] = '\0';
return buffer;
}
INPUT: Commands.txt
i "Willy Wonka's Chochlate Factory"
INPUT testFile.txt
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
Thanks!
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
This is probably your main issue. You allocate enough space for two characters and then proceed to store lots more than that. You probably wanted:
char *output = malloc(strlen(token) + 1);
Since token is a char*, *token is a char. So sizeof(*token) is sizeof(char) -- definitely not what you want.
You almost certainly have a buffer overrun in some part of the code that you're not showing us. If I were to guess, I'd say you allocate too little storage for token to contain the full string you're writing into it in the first place.
Did you by any chance allocate token using the same erroneous code you have in removeInvalid():
malloc(sizeof(100) + 1);
^^^^^^^^^^^ this doesn't allocate 101 characters, it allocates sizeof(int)+1
char *readHelper(FILE *in){
char * token = malloc(sizeof(char *) + 1);
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
It's hard to make sense of this without being able to see readString or readToken, but this can't possibly be right.
First, you allocate one more byte than is needed for a pointer to one or more characters. What use would such a thing be? If you're not storing a pointer to one or more characters, why use sizeof(char *)? If you are storing a pointer to one or more characters, why add one? It's hard to imagine the reasoning that lead to that line of code.
Then, in the if, you immediately lose the value you got back from malloc because you overwrite token by using it to store something else. If you weren't going to use the value you assigned to token, why did you assign it at all?
Bluntly, a lot of this code simply doesn't make any sense. Without comments, it's hard to understand the reasoning so we could point out what's wrong with it.
Either there was reasoning behind that line of code, in which case it's just completely wrong reasoning. Or worse, the line of code was added with no reasoning in the hopes it would work somehow. Neither method will produce working code.
When you're trying to debug code, first remove anything you added experimentally or that you didn't understand. If you do understand malloc(sizeof(char *) + 1), then please explain what you think it does so that your understanding can be corrected.
Why did you think you needed a buffer that was one byte larger than the size of a pointer to one or more characters?
With the help of David Schwartz and the other posters I was able to find the bug in my problem. When I was allocating memory for my token/output, I wasn't allocating enough space.. Using the erroneous code of
malloc(sizeof(100) + 1);
and
malloc(sizeof(*token) + 1);
both of which produced only a couple of bytes to be allocated. This caused a buffer problem causing random letters and numbers/ truncation to happen. The first resulting in the space equivalent to int + 1 and the second in char + 1. (as I was taking the sizeof token which is just the size of what it originally started as, a char)
To fix this I changed the allocation of my token variable to that of
malloc(strlen(token) + 1);
This allocates a space equivalent to the "string" length of token + 1. Allowing the appropriate space for my problem which would end up with space of <= token.
I'm trying to write a code that goes through a given string using a pointer to parse it.
The original code I wrote worked fine but it was... redundant so I tried making it into a function call to make it more concise. Here is what i have:
char inputArray[300];
char buffer[300];
char username[100];
char password[100];
char name[100];
int i=0;
void repeat(char *to)
{
while(*to!='=')
{
to++;
}
}
void array(char *mm,char *tt)
{
i=0;
while(*tt!='+')
{
mm[i]=*tt;
tt++;
i++;
}
}
int main()
{
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
scanf("%s",inputArray);
strcpy(buffer,inputArray);
char *tok=buffer;
repeat(tok);
tok++;
array(username,tok);
repeat(tok);
tok++;
array(password,tok);
tok++;
repeat(tok);
tok++;
array(name,tok);
}
For some reason it won't give me back the pointer array tok where it left off from the previous function call. why is that? it acts as if after calling it the pointer starts back from the beginning.
Functions receive copies of their arguments. Original arguments remain unaffected.
Giving something back has a special syntax in C: the return statement. Thus
char* repeat (char *to) // <- this function gives back a char*
{
while (*to != '=')
{
to++;
}
return to; // <- giving something back
}
Call it like this:
tok = repeat(tok);
Treat array in the same fashion.
Note 1, this function will result in *undefined behaviour if the string doesn't contain '='.
Note 2, it is also possible to pass a pointer to tok as the other answer suggests, but for sake of clarity it is only recommended to use this style when you need to return more than one thing from a function.
just change your repeat to this:
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
and call it like this:
repeat(&tok);
and always check for errors:
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
and your sample code (and add check for errors in array and repeat to not go out of bounds):
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char inputArray[300];
char buffer[300];
char username[300];
char password[300];
char name[300];
int i = 0;
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
void array(char *mm, char *tt){
i = 0;
while (*tt != '+') {
mm[i] = *tt;
tt++;
i++;
}
}
int main() {
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
inputArray[299] = 0;
strcpy(buffer, inputArray);
char *tok = buffer;
repeat(&tok);
tok++;
array(username, tok);
repeat(&tok);
tok++;
array(password, tok);
tok++;
repeat(&tok);
tok++;
array(name, tok);
}
and you may use this to not go out of bounds:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char* read_str(char *src, char *dst){
char *p, *q;
p = src;
while (*p != 0 && *p != '=') p++;
if (*p == 0) {
*dst = 0;
return NULL; // '=' not found
}
p++;
q = p;
while (*q != 0 && *q != '+') q++;
//if (*q == 0) return NULL;// '+' not found
while (p <= q) *dst++ = *p++;
dst--;
*dst = 0;
q++;
return q;
}
#define MAX_LEN 100
int main() {
char username[MAX_LEN];
char password[MAX_LEN];
char name[MAX_LEN];
char inputArray[MAX_LEN] = "username=Alex+password=123+real=Alex";
char *p = inputArray;
p = read_str(p, username);
if (p == NULL)return 1; // error
p = read_str(p, password);
if (p == NULL)return 1; // error
read_str(p, name);
printf("username: %s \n", username);
printf("password: %s \n", password);
printf(" name: %s \n", name);
}
I'm new to C. I'm having some trouble understanding some fundamental materials in reading input and pointers. I want to use a nextChar() function to read and print each character of a string that I enter in the command line. I try typing "hello"..It displays "hello" 6 times. Can someone tell me why this happens? How can I fix it? Thank you for your time!
#include <stdio.h>
#include <assert.h>
char nextChar(char* ptr)
{
static int i = -1;
char c;
++i;
c = *(s+i);
if ( c == '\0' )
return '\0';
else
return c;
}
void display(char* ptr)
{
assert(ptr != 0);
do
{
printf("%s", ptr);
} while (nextChar(ptr));
}
int main(int argc, const char * argv[])
{
char* ptr=argv[1];
display(ptr);
return 0;
}
The %s format specifier instructs printf to print an array of chars, until it finds a null terminator. You should use %c instead if you want to print a single char. If you do this, you'll also need to use the return value from nextChar.
Alternatively, more simply, you could change display to iterate over the characters in your string directly
void display(char* ptr)
{
assert(ptr != 0);
do
{
printf("%c", *ptr); // print a single char
ptr++; // advance ptr by a single char
} while (*ptr != '\0');
}
Or, equivalently but with less obvious pointer arithmetic
void display(char* ptr)
{
int index = 0;
assert(ptr != 0);
do
{
printf("%c", ptr[index]);
index++;
} while (ptr[index] != '\0');
}
the nextchar function could be reduced:
char nextChar(char* ptr)
{
static int i = 0;
i++;
return (*(ptr+i));
}
and display to
void display(char* ptr)
{
assert(ptr != 0);
char c = *ptr;
do
{
printf("%c", c);
} while (c = nextChar(ptr));
}
#include <stdio.h>
#include <assert.h>
char nextChar(const char* ptr){
static int i = 0;
char c;
c = ptr[i++];
if ( c == '\0' ){
i = 0;
}
return c;
}
void display(const char* ptr){
char c;
assert(ptr != 0);
while(c=nextChar(ptr)){
printf("%c", c);
}
}
int main(int argc, const char * argv[]){
const char* ptr=argv[1];
display(ptr);
return 0;
}
This is the output of my program:
Username: paolo
Password: paolo
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
No user or password inside the database;
And this is my program:
int main(void){
int isok = -1;
char *user = NULL, *pass = NULL;
printf("Username: ");
if(scanf("%m[^\n]%*c", &user) == EOF){
perror("scanf user");
return EXIT_FAILURE;
}
printf("Password: ");
if(scanf("%m[^\n]%*c", &pass) == EOF){
perror("scanf");
free(user);
return EXIT_FAILURE;
}
isok = check_login(user, pass);
if(isok == 0){
/* some code here */
}
else{
/* some code here */
}
return EXIT_SUCCESS;
}
int check_login(char *u, char *p){
int retval = -1;
FILE *fp = NULL;
char *tmp, *tmp2, *line = NULL;
/* some code here */
while(fgets(line, 255, fp) != NULL){
tmp = strtok(line, " ");
if(tmp == NULL){
perror("strtok 1");
free(u);
free(p);
free(line);
free(fp);
return -1;
}
tmp2 = strtok(NULL, "\n");
if(tmp2 == NULL){
perror("strtok 2");
free(u);
free(p);
free(line);
free(fp);
return -1;
}
retval = hash_pwd(p, (unsigned char *)tmp2);
if((strcmp(tmp,u) == 0) && (retval == 0)){
free(line);
free(fp);
return 0;
}
else{
continue;
}
}
return -1;
}
int hash_pwd(char *to_hash, unsigned char *tocheck){
SHA256_CTX context;
unsigned char md[SHA256_DIGEST_LENGTH];
size_t length = strlen((const char*)to_hash);
int i;
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char*)to_hash, length);
SHA256_Final(md, &context);
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
printf("%02x", md[i]);
}
printf("\n%s\n", tocheck);
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
if(md[i] == tocheck[i]) continue;
else return 1;
}
return 0;
}
Why my comparision inside the function hash-pwd doesn't work?What am i doing wrong?
The reason it is not working is that one is a pointer to an ascii string that contains a hex value; and the other is an array of binary value (which you are printing as hex).
....
// print out the digest - a binary array of SHA256_DIGEST_LENGTH
// bytes printed in hex
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
printf("%02x", md[i]);
}
// A string of SHA256_DIGEST_LENGTH *2 + 1 length - containing
// the value in hex spelled out in ascii.
printf("\n%s\n", tocheck);
So you need to convert either to the other. And then compare.
How do you know that the hash comparison is failing? It could just as well be the strcmp() call:
if((strcmp(tmp,u) == 0) && (retval == 0)){
For instance, are you sure tmp doesn't contain a newline that is missing in u?
Also, not sure if you're handling the hash loading properly, if you have a long string of hex characters in the file, that will need to be converted to binary before being
compared. The hash computed by SHA256 is binary, not hex string.
There are two (in my opinion) reasonable ways of fixing this:
Convert the hash read from the file to binary, before comparing
Convert the hash computed at runtime to text, before comparing
You can see that the two solutions are each other's complement, which seems natural to me. I would not encourage the solution you mentioned in a comment, involving temporary files.
Of the above, the second one is probably the easiest to implement, since it's easier to convert a bunch of bytes into hex than doing the reverse. It's the solution I would go with, something like:
static int hash_to_string(char *output, size_t output_max,
const unsigned char *hash, size_t hash_size)
{
size_t i;
if(output_max < 2 * hash_size + 1)
return 0;
for(i = 0; i < hash_size; ++i)
sprintf(output + 2 * i, "%02x", hash[i] & 0xff);
output[2 * i] = '\0';
return 1;
}
call the above with a pointer to a buffer large enough to hold the string version, then compare that against the one loaded from the file.
UPDATE: Or, you can use the existing API and just call SHA256_End() to get the hash in hex.
As a general observation, don't do this:
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
if(md[i] == tocheck[i]) continue;
else return 1;
}
return 0;
instead, do this:
return memcmp(md, tocheck, sizeof md) != 0;