I am new to C, and I have been going through the CS50 course to learn some basics. I have been trying to solve the challenge which requires you to make a simple password cracker, but I ran into a problem which prevents me from writing a function program: every time I call the crypt function in my for loop, it somehow breaks my password string that I am iterating through.
I have tried making a copy of the password string, and passing that as an argument to crypt; I have also tried moving the crypt call into a separate function and calling that from the loop (as well as the combination of the two)
#define _XOPEN_SOURCE
#include <unistd.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
string buildLetterDictionary();
int main(int argc, string argv[])
{
if (argc == 2)
{
printf("Two arguments, starting test...\n");
char password[2];
string letters = buildLetterDictionary();
for(int i = 0; i < 5; i++)
{
password[0] = letters[i];
password[1] = '\0';
printf("Password: %s\n", password);
string hashed = crypt(password, "50");
printf("\n%i\nOriginal: %s\nHashed: %s\n", i, password, hashed);
}
return 0;
}
else
{
printf("Usage: ./crack hash");
return 1;
}
}
string buildLetterDictionary()
{
char letters[27];
for(int i = 65; i < 91; i++)
{
letters[i-65] = i;
}
letters[26] = '\0';
string letter = letters;
return letter;
}
if I comment out the lines:
string hashed = crypt(password, "50");
printf("\n%i\nOriginal: %s\nHashed: %s\n", i, password, hashed);
The code works as expected, and produces the output:
A
B
C
D
E
But if I leave those lines in, the password is printed out as 'A' with the hash "50pe4e2XTIS/g" the first time, but every subsequent time is printed out as "" with the hash "50sXZPq5euCxs"
Please let me know what the underlying problem is, so that I may work towards resolving it! Thanks for any help in advance!
I am guessing here that cs50.h contains some definitions like a type alias from char * to string that the professor is giving you for simplicity.
If that is true, then buildLetterDictionary() cannot work, because you are doing:
char letters[27];
...
char * letter = letters;
return letter;
This means you are returning the address of a local variable, which will be destroyed as soon as you leave the function.
Related
How do I take argv[1] from main so that I can use it in my function called only_digits? You don't have to show it to me on my code. I would just like to see, how argv[1] (that is stored in main) can be used in a function (outside of main).
It is also the first time I've used a bool function. I'm wondering if, in the <cs50.h> library, you can use strings and bools the way I used them here. Am I using them right?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
bool only_digits(string);
int x;
int main(int argc, string argv[])
{
string s = argv[1];
x = only_digits(s);
if (x == 1)
{
printf("True\n");
}
else if (x == 0)
{
printf("False\n");
}
}
bool only_digits(string s);
{
for (i= 0; i < strlen(s); i++)
{
if (isdigit(s [i]))
{
return 1;
}
else if (!isdigit(s [i]))
{
return 0;
}
}
}
Your code is really close to being correct. There are a couple of things:
remove the semicolon from the definition of only_digits.
bool only_digits(string s);
{
should be:
bool only_digits(string s)
{
make the i in the loop an int.
for( i =
should be:
for( int i =
fix the logic in the loop so it returns false (aka 0) if any character is not a digit, else if it gets all the way through the loop return true.
bool
only_digits (string s)
{
for (int i = 0; i < strlen (s); i++)
{
if (!isdigit (s[i]))
{
return 0;
}
}
return 1;
}
How do I take argv[1] from main so that I can use it in my function called only_digits?
In your main, the expression argv[1] designates an object of type string. You can do with it anything that you can do with any other string, including pass it as a function argument. Your only_digits() function expects an argument of type string, so you don't need to do anything special to pass argv[1] to it. This will work fine:
x = only_digits(argv[1]);
You can also assign argv[1] to a variable of type string, and then pass the value of that variable, as the code you present does. That's needlessly roundabout, but it will work fine, too.
However, if your function is intended to determine whether all the characters in the string that is passed to it are decimal digits, then it is buggy, as other answers describe in more detail. Loop notwithstanding, it decides what value to return based only on the first character in its input string, because either one or the other conditional inside the loop must evaluate to true no matter what that character is, and the function returns either way. It also fails to return anything at all in the event that an empty string is passed to it.
Note also that CS50 makes the unfortunate choice of using string as an alias for type char *. This is perhaps easier to read, and it defers the need to talk about pointers, but it sets students up for confusion later on when they discover that strings seem to behave differently than objects of most other data types.
It is also the first time I've used a bool function. I'm wondering if, in the <cs50.h> library, you can use strings and bools the way I used them here. Am I using them right?
There is nothing inherently wrong with the way you are using string and bool. Probably the compiler would warn you if there were, or even outright reject the code. Your program produces different results than you expect because it contains logic errors.
You ask two questions.
First, there's no need for string s. argv[] is an array of pointers to strings, so you could pass the string of interest like so:
x = only_digits( argv[1] );
BUT, before using it, you must test that the user has supplied a string:
if( argc == 2 )
x = only_digits( argv[1] );
Second, returning 1 for true or 0 for false, will work, but you should use the tokens that mean boolean results.
return true; // or return false;
Here's a version that moves the function ahead of its invocation. In this way, there's no need for a function prototype.
bool only_digits( string s )
{
while( isdigit( *s ) )
s++;
// TRUE if reached end of string
if( *s == '\0' )
return true;
return false;
}
void main( int argc, string argv[] )
{
if( argc == 2 && argv[1][0] != '\0' && only_digits( argv[1] ) )
printf( "True\n" );
else
printf( "False\n" );
}
The semicolon(;) needs to be removed:
bool only_digits(string s)
{
for (i= 0; i < strlen(s); i++)
{
if (isdigit(s[i]))
{
return 1;
}
else
{
return 0;
}
}
}
and you can simply use else in place of else if because if s[i] is not
A digit, then it doesn't matter what it is we just need to return false or 0 in that condition
I am new to coding (I just started this year), so please forgive me for any dumb mistakes. However, my goal is to make some straightforward code to have users enter their username and password. I would like the username to have 8 characters,1 uppercase, 1 lowercase, 1 digit, and 1 symbol. I thought my code was good but I keep running into an issue where I keep getting an error that says, "array must be initialized with a brace enclosed initializer". If you can find where I can improve, and what the issue might be it would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
char username[20];
char password[20];
bool verify_password(char *password)
{
int length = strlen(password);
if (length < 8) return false;
bool has_upper = false;
bool has_lower = false;
bool has_digit = false;
bool has_symbol = false;
for (int i = 0; i < length; i++)
{
if (isupper(password[i])) has_upper = true;
if (islower(password[i])) has_lower = true;
if (isdigit(password[i])) has_digit = true;
if (ispunct(password[i])) has_symbol = true;
}
if (!has_upper) return false;
if (!has_lower) return false;
if (!has_digit) return false;
if (!has_symbol) return false;
return true;
}
int main()
{
printf("please enter your new username:\n");
scanf("%s", username);
printf("please enter your password(must be 8 characters,1 uppercase, 1 lowercase, 1 digit, and 1 symbol):\n");
scanf("%s", password);
char password[strlen(password)] = password;
bool result = verify_password(password);
if (result)
{
printf("password has been verified\n");
}
else
printf("missing element described");
printf("welcome to your account %s!, your password is %s", username, password);
return 0;
}
The compiler is saying that arrays need to be initialized with = { ... };
char password[strlen(password)] is an array, specifically a variable-length array (VLA). However, these arrays are special since they cannot get initialized at all. You have to set their values at run-time
Furthermore, it has to be char password[strlen(password)+1] so there's room for the null terminator.
Furthermore, you need to assign a value to a string using strcpy, not with the = operator.
Furthermore, you cannot have several variables with the same name. Or well you can, but in case of char password[strlen(password)] = password;, the password refers to the local variable, not the global one. It's a bad idea to use global variables in general and this would be one of many reasons why.
Overall you cannot do C programming by trial & error. There's no "take a chance and type something that looks ok", you need to actually know what every single thing you write does and that it is valid C.
I am fairly new to C and have been trying my hand with some arduino projects on Proteus. I recently tried implementing a keypad and LCD interface with Peter Fleury's libraries, so far the characters I input are displayed fine, but I run into a problem when trying to print to the serial port. It's like the value of the keys keeps on being concatenated with every iteration so the ouput has extra characters like this:
The value before the comma is from the 'key' variable, the value after it the 'buf' variable:
151
(The 5 I input in the second iteration was added to the 1 from the first iteration and then put into the variable I print)
I figure it may be due to my lack/incorrect use of pointers, heres is my code:
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdio.h>
#include "lcd.h"
#include "mat_kbrd.h"
#include "funciones.h"
#include "menu.h"
char buf[256];
char* coma = ",";
int main(void)
{
pin_init();
serial_begin();
lcd_init(LCD_DISP_ON);
kbrd_init();
bienvenida();
while (1) {
int i = 0;
char key = 0;
//char *peso;
//int pesoSize = 1;
char peso[100];
//peso = calloc(pesoSize,sizeof(char));
int salida = 0;
lcd_clrscr();
desechos();
key = kbrd_read();
if (key != 0) {
lcd_gotoxy(0,3);
lcd_putc(key);
_delay_ms(2000);
lcd_clrscr();
cantidad();
while (salida != 1) {
char keypeso = 0;
keypeso = kbrd_read();
//pesoSize = i;
//peso = realloc(peso,pesoSize*sizeof(char));
if (keypeso != 0) {
if (keypeso == '+') {
salida = 1;
keypeso = *("");
lcd_clrscr();
calcularTotal(key,peso);
_delay_ms(2000);
} else {
lcd_gotoxy(i,1);
lcd_putc(keypeso);
snprintf(peso, sizeof peso, "%s%s",peso, &keypeso);
//strcat(peso,&keypeso);
i++;
_delay_ms(2000);
}
}
}
snprintf(buf, sizeof buf, "%s%s%s", &key,coma,peso);
serial_println_str(buf);
}
}
}
&key and &keypeso point to a single char, but you are using the %s format specifier, so trying to read a string into a single char. Use %c rather then %s for single characters, and pass the char not the address-of-char..
I am trying (and having trouble) to write a program (In C) that accepts a string in the command line (eg. $ test.out "This is a string") and looks through the string to find verbs (and nouns, but if I figure out verbs, I can do nouns on my own).
A list of aplphabetically sorted verbs is given in the file lexicon.h, and is what I am supposed to use as my dictionary.
I know how to accept the string from the command line and use that input to create an array of strings, each string itself being a separate word, and I already have a working program that can do that, and that I hope to use part of for this one.
I am supposed to create a function called binary_search(...stuffgoeshere...) and use that to search through the lexicon file and find the verb.
I would like some suggestions or guidance on how to create a function (binary_search) that can check to see if an already separated word matches any on the list in lexicon.h. I do not want someone to just write an answer, I would like to know why you are suggesting what you do. Hopefully I can learn something fun out of this!
I know it's messy, but this is what I have so far.
Also note that lexicon's verb array has 637 values (as seen when I make int size = 637)
This program does not compile anymore, as I have not yet figured out how to make the binary_search function work yet. I am trying to modify a binary search function used in an example for class, however, that one sorted numbers in a text file, not strings of characters.
If there is anything else I should include, let me know. Thank you for your help!
#include <stdio.h>
#include <string.h>
#include "lexicon.h"
int binary_search(char word[], char verbs[][], int size);
int
main(int argc, char*argv[])
{
char word[80];
char str[80],
args[80][80];
int counter = 0,
a = 0,
i = 0,
index = 0,
t = 0;
while(str[a] != '\0')
{
if(str[a] == ' ')
{
args[index][i] = '\0';
i = 0;
a++;
index ++;
counter ++;
}
args[index][i++] = str[a++];
}
args[index][i] = '\0';
counter = counter + 1;
printf("\nThe verbs were: ");
int verbposition= -1;
int size = 637;
while(t<counter)
{
strcpy(word, args[t]);
verbposition = binary_search(word, verbs, size);
if(verbposition > -1)
printf("%s", args[t]);
t++;
}
return 0;
}
int
binary_search(char word[], char &verbs[][], int size)
{
int bottom = 0,
top = size - 1,
found = 0,
middle;
while(bottom <= top && !found)
{
middle = (bottom + top) / 2;
if(strcmp(word, verbs[middle]))
{
found = 1;
return = middle;
}
if(strcmp(word, verbs[middle]) > 0)
{
top = middle - 1;
}
else
bottom = middle + 1;
}
return -1;
}
You are on the right track. I would highly suggest you to use print statements as you will have a clear idea of where you are going wrong.
Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !