C: Comparing hash value seems to disappear - c

For the love of holy code, I am trying to compare hashes to find the correct password. I am given a hash as a command line argument, and I then hash words from "a" to "ZZZZ" until one of the hash pairs match.
void decipher(string hash)
{
//Set the password, and the salt.
char pass[4] = "a";
char salt[] ="50";
//Compare the crypted pass againts the hash until found.
while (strcmp(hash,crypt(pass, salt)) != 0)
{
//Use int i to hold position, and return next char
int i = 0;
pass[i] = get_next(pass[i]);
tick_over (pass, i);
//Hardcode in a fail safe max length: exit.
if (strlen(pass) > 4)
{
break;
}
}
printf("%s\n", pass);
}
The problem is that it will not 'catch' the correct password / comparison, when that password is 4 letters long. It works for 1,2 and 3 letter long words.
//Tick over casino style
string tick_over (string pass, int i)
{
//Once a char reaches 'Z', move the next char in line up one value.
char a[] = "a";
if (pass[i] == 'Z')
{
if (strlen(pass) < i+2)
{
strncat (pass, &a[0], 1);
return pass;
}
pass[i+1] = get_next(pass[i+1]);
//Recursively run again, moving along the string as necessary
tick_over (pass, i+1);
}
return pass;
}
//Give the next character in the sequence of available characters
char get_next (char y)
{
if (y == 'z')
{
return 'A';
}
else if (y == 'Z')
{
return 'a';
}
else
{
return y + 1;
}
}
It does iterate through the correct word, as I have found in debugging. I have tried moving the
strcmp(hash, crypt(pass, salt)) == 0
into a nested if statement among other things, but it doesn't seem to be the problem. Is c somehow 'forgetting' the command line value? When debugging the hash value seemed to have disappeared :/ Please help!

char pass[4] = "a"; you're defining a char array which can contain at most 3 chars + null terminator.
that's not coherent with your "safety" test: if (strlen(pass) > 4)
When strlen is 4 the array is already overwriting something in memory because of the null termination char: undefined behaviour.
Quickfix: char pass[5] ...

Here is the explanation of the function strncat:
Append characters from string
Appends the first num characters of source to destination, plus a terminating null-character.
with a size of 4 you are not considering the terminating null character of your four chars array.

Related

How to modify the characters in a char array

My intention was to use the command line to read input and store it into an array and modify the characters of the array. If the character is '1', then turn it into '0', vice versa. I successfully store the input into an array, yet failed to modify the characters of the array. If I put 0000000000000000000000000000000(32bits) into my program, the output doesn't change.
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *a = argv[argc-1];
char arr[33];
size_t length = strlen(a);
for(size_t i=0;i<length;i++) {
arr[i]=a[i];
}
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
if(arr[j]=='1') {
arr[j]='0';
}
}
for(int k=0;k<32;k++) {
printf("%c",arr[k]);
}
}
If I put 0000000000000000000000000000000(32bits) into my program, the output doesn't change.
First of all, your program is not processing bits of input but it is processing the characters of input you are passing as command line argument to your program. If you want to process the bits of input, to start with, read about bitwise operators first.
Look at this for loop:
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
if(arr[j]=='1') {
arr[j]='0';
}
}
If current processing arr element value is '0', the second if condition in the for loop body will nullify the effect of first if condition on that arr element i.e. the arr element value will be unchanged and if the current processing arr element value is '1' than it will be set to '0'. So, after the loop, all the elements of array arr, which have original value as either '1' or '0', will set to '0' and that's the flaw in your logic.
Few suggestions:
If program is supposed to receive command line argument('s), make sure to put check on argc value. In your case, user is supposed to pass the string comprised of '0's and '1's, so you should check on argc value, something like:
if (argc != 2) {
printf ("Usage: <exe_name> <string_of_0s_and_1s>\n");
return 1;
}
Since, you do not have check on argc value in your program, if user do not pass any string from command line, the value of argc may be 1 and ,in this case, argv[argc-1] (or argv[0]) represents the program name or if the program name is not available from the host environment than argv[0][0] will be the null character. If argv[0] represents program name whose length is greater than 32 characters then your program will land up in undefined behaviour territory because there is no check on whether the command line input string length is <= 32 characters while copying it to arr buffer.
Since you are copying the input to char array (not as string) declare arr as array of 32 characters and not 33 characters. Looks like, you have assumed the input will be of size <= 32 characters. There is no problem with this assumption as long as program is running in a controlled environment where you are taking care of it. But still, by chance, if input string length is > 32 characters then your program behaviour will be undefined as it will end up processing array arr beyond it's size. You should add a check on length of input string as well:
if (length > 32) {
printf ("Input string length is >= 33 character.\n" \
"The permitted input string length is <= 32 characters.\nExiting..\n");
return 1;
}
If you want the input string to be of exact 32 characters, you can add check if (length != 32).
While copying the string, you can also add check on the characters of input string and if it contain character other than '1' and '0' then throw error message and exit.
Putting these altogether :
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]) {
char *a = NULL;
char arr[32];
if (argc != 2) {
printf ("Usage: <exe_name> <string_of_0s_and_1s>\n");
return 1;
}
a = argv[argc-1];
size_t length = strlen(a);
if (length > 32) {
printf ("Input string length is > 32 characters.\n" \
"The permitted input string length is <= 32 characters.\nExiting..\n");
return 1;
}
for (size_t i = 0; i < length; i++) {
if ((a[i] != '1') && (a[i] != '0')) {
printf ("Found a character other than characters '1' and '0' in the input string.\n" \
"The input string should comprised of characters `1' and '0' only.\nExiting..");
return 1;
}
arr[i] = a[i];
}
for (size_t j = 0; j < length; j++) {
if (arr[j] == '0') {
arr[j] = '1';
} else {
arr[j] = '0';
}
}
for (size_t k = 0; k < length; k++) {
printf ("%c", arr[k]);
}
return 0;
}
you forget to give an else if condition in this part of the code.
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
else if(arr[j]=='1') { //This part should be else if
arr[j]='0';
}
}
In your code for the value of 0 it changed to 1. But for another if condition the value changed to 0 again.
To copy string you need to copy null character as well.
size_t length = strlen(a);
14 for(size_t i=0;i<=length;i++){
15 arr[i]=a[i];
But you do not need to traverse the string twice
size_t i=0;
while((arr[i]=a[i])) i++;
Your if is wrong. It should be
if(arr[j]=='0') arr[j]='1';
else arr[j]='0';

CS50 / BEGINNER - Segmentation fault in nested for loop in C

I'm trying to write code that will take each digit from a plaintext string input and, if it is a letter, output a different letter, as defined by a substitution key (26-letter key).
In other words, if the alphabet was "abcd" and provided key was "hjkl", an input of "bad" would output "jhl".
// Regular alphabet is to be used as comparison base for key indexes //
string alphabet = "abcdefghijklmnopqrstuvwxyz";
// Prompt user for input and assign it to plaintext variable //
string plaintext = get_string("plaintext: ");
Non-letters should be printed as-is.
My idea was to loop the input digit through every index in the alphabet looking for the corresponding letter and, if found, print the same index character from the string. (confusing, I think)
This loop, however, returns a segfault when I run it, but not when debugging:
// Loop will iterate through every ith digit in plaintext and operate the cipher //
for (int i = 0; plaintext[i] != '\0'; i++) {
// Storing plaintext digit in n and converting char to string //
char n[2] = "";
n[0] = plaintext[i];
n[1] = '\0';
// If digit is alphabetic, operate cipher case-sensitive; if not, print as-is //
if (isalpha(n) != 0) {
for (int k = 0; alphabet[k] != '\0'; k++) {
char j[2] = "";
j[0] = alphabet[k];
j[1] = '\0';
if (n[0] == j[0] || n[0] == toupper(j[0])) {
if (islower(n) != 0) {
printf("%c", key[k]);
break;
} else {
printf("%c", key[k] + 32);
break;
}
}
}
} else {
printf("%c", (char) n);
}
}
What's going wrong? I've looked for help online but most sources are not very beginner-friendly.
Your code seems to be working except one error: The program crashes at
isalpha(n)
Cause you declared
char n[2]
the parameter there is a pointer of type char*. But islower only accepts an int parameter, so just write it as
isalpha(n[0])
Same for islower.

How do I count the number of sentences in C using ".", "?", "!"?

I'm fairly new to coding. I'm having trouble with my "CountSentences" function. I compare the string to "." , "?" , and ! to count a sentence. It only adds one to the sentence counter no matter how many of the punctuation marks I have in the string. Am I using strcmp wrong to get my desired result and is there another way I can approach this?
#include<cs50.h>
#include<ctype.h>
#include<string.h>
#include<math.h>
//function for letter count
int count_letters(string s)
{
int numberofLetters = 0; // counter
//loop as long as string length
for(int i = 0, n = strlen(s); i < n; i++)
{
//if character is alphanumeric
if(isalnum(s[i]) != 0)
{
numberofLetters++; //increase counter
};
};
return numberofLetters; //return new counter number
};
//function for word count
int count_Words(string w)
{
int numberofWords = 0;//counter for words declared
int i = 0; // counter for character in string
if(w == NULL) // if nothing
{
return numberofWords; // return Wordcount of 0
};
bool spaces = true; //truth value for space
//if character is not null terminating character
while(w[i] != '\0')
{
if(isblank(w[i]) != 0) //if character is blank
{
spaces = true; //its a space
}
else if(spaces) //if no more space and a letter is present add to words
{
numberofWords++; //add to number of words counter
spaces = false;
};
i++;// increase chracter count in string w
};
return numberofWords; //return total word counter
};
//function to count sentences
int count_Sentences(string l)
{
//variable counter for marks
int countMarks = 0;
//loop iteration using the number of characters in string
for(int i = 0, n = strlen(l); i < n; i++)
{
//check if character is ?, . , or !
if(strcmp(&l[i], "!") == 0 || strcmp(&l[i], ".") == 0 || strcmp(l, "?") == 0)
{
countMarks++;// sentence counted
};
};
// return the total number of marks
return countMarks;
};
int main (void)
{
string text = get_string ("Text: ");
//to check the functions bug checker
printf("Number of letters: %i\n", count_letters(text));
printf("Number of words: %i\n", count_Words(text));
printf("Number of sentences: %i\n", count_Sentences(text));
//Coleman Liau Index
int grade = round(0.0588 * (100 * (count_letters(text)) / (count_Words(text))) - 0.296 * (100 *(count_Sentences(text)) / (count_Words(text))) - 15.8 );
if(grade <= 1)
{
printf("Before Grade 1\n");
}
else if(grade < 16)
{
printf("Grade %i\n", grade);
}
else
{
printf("Grade 16+\n");
};
};
if(strcmp(&l[i], "!") == 0 || strcmp(&l[i], ".") == 0 || strcmp(l, "?") == 0)
strcmp compares two strings. In C, our "string" is essentially "the char-sized data starting at the place this pointer points to, and continuing until a null terminator". The cs50 library does not change this and does not give you a real string type; it only provides a typedef and some helper functions for reading input. (It also, sadly, does not and realistically cannot give you a real text character type, which char also is not; but that is beyond the scope of this answer.)
&l[i] is a pointer into the middle of the l string, starting at offset i. When that pointer is used by strcmp, it will treat the "string" as everything from that character to the end of the original string - because that's where the null terminator is. It will, in particular, not treat the single l[i] char as a separate string, in general, because the next char is in general not a null terminator. So,
It only adds one to the sentence counter no matter how many of the punctuation marks I have in the string.
In fact, it only even adds one because your string ends with one of those marks.
To compare individual chars, don't use strcmp. It is not intended nor fit for the purpose. A char is a single entity, so it can be compared just fine with ==. You just need to have something appropriate on both sides of the comparison.
Recall, in C single quotes are used for char literals, and indexing into the char array (equivalently, "indexing" into a char pointer, which performs the equivalent pointer arithmetic) gives you a char. Thus:
if (l[i] == '!' || l[i] == '.' || l[i] == '?')
You indeed need to see if the one character l[i] is any of ., ? or !. To do that, you can test if that is equal to any of these character constants, i.e. l[i] == '!' || l[i] == '.' || l[i] == '?'
Or you can use the function strchr that will look for a given character in a given string and return a pointer to that character, or a null pointer if the character is not found. A null pointer will be considered as falsy in if, and and a non-null pointer truthy. So we can look for l[i] in the string ".?!":
if (strchr(".?!", l[i])) {
...
}

how to fix this code so that it can test the integers present next to the character?

Given a string containing alphanumeric characters, calculate the sum of all numbers present in the string.
The problem with my code is that it displays the integers present before the characters, but it is not summing up the integers after the characters.
The execution is easy in python and C++ but I cant get it done using C! Can anyone please verify where I have done wrong? << thank you !
enter code here
#include<stdio.h>
#include<string.h>
int convert(char[]);
int main()
{
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++)
{
if((ch[i]>='0') && (ch[i]<='9'))
{
temp[j]=ch[i];
j++;
}
else
{
if(temp[0]== '\0')
{
continue;
}
else
{
n=convert(temp);
s+=n;
temp[0]= '\0';
j=0;
}
}
}
printf("%d",s);
return 0;
}
int convert(char s[]) //converting string to integer
{
int n=0;
for(int i=0;i<strlen(s);i++)
{
n= n * 10 + s[i] - '0';
}
return n;
}
Input : 12abcd4
Expected output : 16
But the output is 12 for my code.
There are two problems in your code. The first was mentioned in the comments : if the last character is a digit, the last "number section" will not be taken into account. But I don't think that the solution given in the comments is good because if the last character is not a digit, you will have a wrong value. To correct this, I added an if statement that check if the last character is a digit, if so call convert().
The second problem is that strlen return the number of characters in you string from the beginning until it finds an '\0'. The way you used your string lead to the follow problem :
ch = "12abcd4".
At first you have temp = '1' + '2' + '\0'...
After calling convert() you set temp[0] to '\0', thus temp = '\0' + '2' + '\0'... .
And when you start reading digit again, you set '4' in temp[0]. Your string is now : '4' + '2' + '\0'... .
The n returned will be 42 and your result 54 (12+42). There are several solution to have the expected behavior, I chose to use your variable j to indicate how many characters should be read instead of using strlen() :
#include<stdio.h>
#include<string.h>
int convert(char[], int size);
int main() {
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++) {
if((ch[i]>='0') && (ch[i]<='9')) {
temp[j]=ch[i];
j++;
// change here
if(i == strlen(ch) - 1) {
n=convert(temp, j);
s+=n;
}
}
else {
// change here
n=convert(temp, j);
s+=n;
if(temp[0]== '\0') {
continue;
}
temp[0]= '\0';
j=0;
}
}
printf("%d\n",s);
return 0;
}
//change here
int convert(char s[], int size) {
int n=0;
for(int i=0;i<size;i++) {
n= n * 10 + s[i] - '0';
}
return n;
}
You could use a combination of strtoul() and strpbrk() to do this.
Declare two character pointers start_ptr and end_ptr and make start_ptr point to the beginning of the string under consideration.
char *start_ptr=s, *end_ptr;
where s is the character array of size 100 holding the string.
Since your string has only alphanumeric characters, there is no - sign and hence there are no negative numbers. So we can get away with using unsigned integers.
We are using strtoul() from stdlib.h to perform the string to integer conversion. So let's declare two variables: rv for holding the value returned by strtoul() and sum to hold the sum of numbers.
unsigned long rv, sum_val=0;
Now use a loop:
for(; start_ptr!=NULL; )
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
printf("\nOut of range.");
break;
}
else
{
printf("\n%lu", rv);
sum_val += rv;
start_ptr=strpbrk(end_ptr, "0123456789");
}
}
strtoul() will convert as much part of the string as possible and then make end_ptr point to the first character of the part of the string that could not be converted.
It will return ULONG_MAX if the number is too big and errno would be set to ERANGE.
Otherwise the converted number is returned.
strpbrk() would search for a set of characters (in this case the characters 0-9) and return a pointer to the first match. Otherwise NULL is returned.
Don't forget to include the following header files:
stdlib.h ---> strtoul
string.h ---> strpbrk
limits.h ---> ULONG_MAX
errno.h ---> errno
In short, we could make the program to something like
for(; start_ptr!=NULL; sum_val += rv, start_ptr=strpbrk(end_ptr, "0123456789"))
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
break;
}
}
printf("\n\n%lu", sum_val);
So the value of sum_val for the string "12abcd4" would be 16.
scanf() is usually not the best way to accept input that is not well-formatted. Maybe you can use fgets()-sscanf() combo instead.
If you must use scanf(), make sure that you check the value returned by it, which in your case must be 1 (the number of successful assignments that scanf() made).
And to prevent overflow, use a width specifier as in
scanf("%99s",ch);
instead of
scanf("%s",ch);
as 100 is the size of the ch character array and we need one extra byte to store the string delimiter (the \0 character).

Trying to remove all numbers from a string in C

I'm trying to take all of the numbers out of a string (char*)...
Here's what I have right now:
// Take numbers out of username if they exist - don't care about these
char * newStr;
strtoul(user, &newStr, 10);
user = newStr;
My understanding is that strtoul is supposed to convert a string to an unsigned long. The characters that are not numbers are put into the passed in pointer (the 2nd arg). When i reassign user to newStr and print it, the string remains unchanged. Why is this? Does anyone know of a better method?
From the documentation example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[30] = "2030300 This is test";
char *ptr;
long ret;
ret = strtoul(str, &ptr, 10);
printf("The number(unsigned long integer) is %lu\n", ret);
printf("String part is |%s|", ptr);
return(0);
}
Let us compile and run the above program, this will produce the following result:
The number(unsigned long integer) is 2030300
String part is | This is test|
char* RemoveDigits(char* input)
{
char* dest = input;
char* src = input;
while(*src)
{
if (isdigit(*src)) { src++; continue; }
*dest++ = *src++;
}
*dest = '\0';
return input;
}
Test:
int main(void)
{
char inText[] = "123 Mickey 456";
printf("The result is %s\n", RemoveDigits(inText));
// Expected Output: " Mickey "
}
The numbers were removed.
Here is a C program to remove digits from a string without using inbuilt functions. The string is shifted left to overwrite the digits:
#include <stdio.h>
int main(void) {
char a[] = "stack123overflow";
int i, j;
for (i = 0; a[i] != '\0'; i ++) {
if (a[i] == '0' || a[i] == '1' || a[i] == '2' || a[i] == '3' || a[i] == '4' || a[i] == '5' || a[i] == '6' || a[i] == '7' || a[i] == '8' || a[i] == '9') {
for (j = i; a[j] != '\0'; j ++)
a[j] = a[j + 1];
i--;
}
}
printf("%s", a);
return 0;
}
Example of execution:
$ gcc shift_str.c -o shift_str
$ ./shift_str
stackoverflow
strtoul() does not extract all numbers from string, it just trying to covert string to number and convertion stops when non digit is find. So if your string starts from number strtoul() works as you expect, but if string starts from letters, strtoul() stops at the first symbol. To solve your task in simple way you should copy all non-digits to other string, that will be a result.
The problem you are having is that strtoul is converting characters at the beginning of the string into an unsigned long. Once it encounters non-numeric digits, it stops.
The second parameter is a pointer into the original character buffer, pointing at the first non-numeric character.
http://www.cplusplus.com/reference/cstdlib/strtoul/
Parameter 2 : Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
So, if you tried to run the function on "123abc567efg" the returned value would be 123. The original string buffer would still be "123abc567efg" with the second parameter now pointing at the character 'a' in that buffer. That is, the pointer (ptr) will have a value 3 greater than original buffer pointer (str). Printing the string ptr, would give you "abc567efg" as it simply points back into the original buffer.
To actually remove ALL the digits from the string in C you would need to do something similar to this answer : Removing spaces and special characters from string
You build your allowable function to return false on 0-9 and true otherwise. Loop through and copy out digits to a new buffer.

Resources