How to pass argv[1] from main into a function? - c

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

Related

Finding indexes where substring is present

So right now my code checks if the sub string is present in the code and returns true or false, I would like to find where these substrings are located in the total string. how can you implement that.
#include <stdio.h>
#include <stdbool.h>
bool checksub(const char *strng,const char *subs){
if (*strng=='\0' && *subs!='\0'){
return false;
}
if (*subs=='\0'){
return true;}
if (*strng==*subs){
return checksub(strng+1,subs+1);
}
return false;
}
bool lsub(char *strng,char *subs){
if (*strng=='\0'){
return false;
}
if (*strng==*subs){
if (checksub(strng,subs)){
return 1;
}
}
return lsub(strng+1,subs);
}
int main(){
printf("%d\n",checksub("ababuu","ab"));
printf("%d\n",checksub("the bed bug bites","bit"));
return 0;
}
First you should get rid of recursion since it's often slow and dangerous, for nothing gained.
A (naive) version of strstr that returns an index rather than a pointer might look like this:
int strstr_index (const char* original, const char* sub)
{
int index = -1;
for(const char* str=original; *str!='\0' && index==-1; str++)
{
for(size_t i=0; str[i]==sub[i] && str[i]!='\0'; i++)
{
if(sub[i+1] == '\0')
{
index = (int)(str - original);
break;
}
}
}
return index;
}
This returns -1 if not found, otherwise an index.
It iterates across the string one character at a time.
When a character match with the sub string is found, it starts executing the inner loop as well.
If the inner loop continues to find matches all the way to the end of the sub string, then we found a match.
The index can be obtained by pointer arithmetic: the start address of the found sub string minus the start of the string. The result of that subtraction is strictly speaking a special integer type called ptrdiff_t, but I used int to simplify the example.

crypt function in C breaking password string in for loop

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.

User entered string run a particular function in c

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 !

How do you use a string array in a conditional statement in C?

I want to use a string array in an if statement to test whether the input string matches any of the strings in the array.
So far this is what I've tried:
void checkForError(char input[50])
{
const char *input2[]={"print","loadStarter","terminate()"};
if(input != input2)
{
printf("Error:Incorrect method '%s'.\n",input);
}
else
{
abort();
}
}
And if I were to enter something in the array like "print" it would end up showing me:
Error:Incorrect method 'print'.
but when I try something not listed in the array like "g" it repeats the error message nonstop.
I was thinking perhaps something like this could work:
void checkForError(char input)
{
if(strcmp(input,"print"))!=0 || strcmp(input,"loadStarter"))!=0 || strcmp(input,"terminate()")
{
printf("Error:Incorrect method '%s'.\n");
}
else
{
abort();
}
}
But it turns out that actually doesn't work so what do I do?
You cannot compare strings (usefully) in C using == and !=; you must use library functions such as strcmp instead. See How to compare strings in an "if" statement? for details.
I think a good solution to your question would be to loop around your array, aborting on the first match.
void checkForError(char* input)
{
const char *input2[]={"print","loadStarter","terminate()"};
const int len = sizeof(input2)/sizeof(input2[0]);
for (int i = 0; i < len ;i ++)
{
if (strcmp(input,input2[i]) == 0)
{
//I have matched the string input2[i]
abort();
}
}
// Nothing matched
printf("Not found\n");
}
This would also be easier to extend than any handcoded method.
Also, if you plan on doing a lot with these strings, and you have a limited number of strings, you should probably turn them into some sort of enum. This way you do not have to have strcmp scattered everywhere, and you can use a standard switch statement.
a better method would be to have a return value then have your error message depend on return value.
// return 1 when string is OK, 0 otherwise:
int checkForError(const char* input)
{
if(!strcmp(input,"print")) || !strcmp(input,"loadStarter")0 || !strcmp(input,"terminate()")
{
return 1;
}
else
{
return 0;
}
}
Your second thought is correct, you should not compare the strings using == operator, anyway, I'm not sure whether the rest is a typo or not, but it should be like that:
void checkForError(char * input)
// ^ note the * (pointer)
{
if(strcmp(input,"print")!=0 || strcmp(input,"loadStarter")!=0 || strcmp(input,"terminate()") != 0)
// you forgot brackets
{
printf("Error:Incorrect method '%s'.\n", input);
// ^ you forgot the "input" parameter
}
else
{
abort();
}
}

Function that searches for difference between members of an array

I need to write a function that will return true if it has found a difference between members of an array.
My code is:
int func1(int *str)
{
int i;
for(i=0;i<*(str+i);i++) {
if(*(str+i) == *(str+i+1))
{
return 1;
}
}
return 0;
}
I have to implement it with pointers.
The code above does not work(logically).
Can anybody help?
UPDATE:
I have changed my code to the following:
int func1(int *str)
{
int i,temp=0;
for(i=0;i<10-1;i++) {
if(*(str+i) == *(str+i+1))
{
temp++;
if( temp == 10 )
{
return 1;
}
}
}
return 0;
}
What is the problem with the new code?
This looks like homework to me, so I don't want to spoil the fun but one thing about C I'd like to mention: having a pointer to some array doesn't tell you anything about the size of the array. So your function will need to take a pointer and a second size_t argument (or maybe a pointer to the last element of the array).
Your function only takes in a single array pointer, that seems like one too few for a comparison.
You must add an argument that specifies the lengths of the arrays, or implement some kind of "policy" that e.g. terminates the arrays using a specific value.
You should also look into using the standard memcmp() function.
I don't understand the question (It's unclear what you're trying to achieve)...
As others have already said, there's no boundary checking on your array, which is wrong...
Here's some other feedback on your code:
// func1 - consider giving functions a meaningful name, it helps people to
// understand what the function is supposed to be doing....
// In this instance, it might have been helpful to identify what the expected
// return values / inputs of the function are...
int func1(int *str)
{
int i;
// Start a counter at 0, loop (adding 1) while
// the current value of the counter is less than, the value held in the
// array so, {1,2,3,4,0,7} Would terminate on the 0
// This: {1,20,7,14,0,7} Would also terminate on the 0
// This seems wrong, but again, it's unclear what you're trying to do here.
for(i=0;i<*(str+i);i++) {
// If the current element of the array
// is the same as the next element of the array
if(*(str+i) == *(str+i+1))
{
// return 1 - two numbers next to each other in the
// array are the same?
return 1;
}
}
// Either: The array contained a digit less than the counter,
// Or: It didn't contain two numbers that were the same next to each other.
// This seems a bit wrong?!?
return 0;
}
Your question could be improved (to get a more useful answer), if you showed what inputs you were expecting to return what return values.
Based on this 'I will need to write a function that will return true if its found diffrence between members of array.'
In pseudo code, it seems like you would want:
// Loop, checking we don't overflow. No point checking the last element as
// there's nothing after it to check...
for (count = 0 to arraysize -1) {
// If the current element != the next element, we've found a difference?!?
if(arrayElement[count] != arrayElement[count+1) {
return true
}
}
return false
UPDATE:
In your new code...
// You're still assuming the size of 'str'
int func1(int *str)
{
int i,temp=0;
// Loop while i < 9, i.e. 9 times.
for(i=0;i<10-1;i++) {
if(*(str+i) == *(str+i+1))
{
temp++;
// Temp can never == 10, you're only going round the loop 9 times...
// Maybe it should be (temp == 10-1), but I don't know where the
// 10 comes from...
if( temp == 10 )
{
return 1;
}
}
}
return 0;
}
This:
if(*(str+i) == *(str+i+1))
{
temp++;
// Temp can never == 10, you're only going round the loop 9 times...
if( temp == 10 )
{
return 1;
}
}
Could be:
// return 0 (FALSE) on first difference
if(*(str+i) != *(str+i+1))
{
return 0;
}
If you changed the return 0 at the end of your function to return 1

Resources