I want to write a very simple calculator in C.
At the start, the variable for the output is 0 and every calculation adjusts the value.
For example if I type -a 5 at the program start the output is 5, if I write -a 5 -s 5 the output is 0.
If I don't choose a or s it will just add all values to the output.
And if I type something like -a 10 -s 5 10 25, the 10 and 25 also should be add to the output.
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int result = 0;
for (int i = 1; i < argc - 1; i++) {
for (int j = i + 1; j < i + 2; j++) {
int value = atoi(argv[j]);
if (strcmp(argv[i], "-a") == 0) {
result += value;
} else
if (strcmp(argv[i], "-s") == 0) {
result -= value;
} else {
result += value;
}
}
}
printf("%d\n", result);
return 0;
}
All works fine, but not when I just type in some numbers without -s or -a.
When I start the program for example with 5 10 25, it will ignore the first number and the output will be 35. I don't really know, how to fix this.
Problems:
The first argument will never be treated as value inside of your program because j in int value = atoi(argv[j]); will ever start with the value of 2, not 1. j is declared and initialized with int j = i + 1; (j gets initialized with the value of i plus one) and since i starts with the value of 1 (int i = 1), j will start with a value of 2.
The inner loop isn't needed at all and literally only mess things up as it is even the source of your main issue already and makes your code harder to read. I highly recommend you to omit it.
For value: Declaring a variable inside a loop isn't a good practice BTW because the variable is declared new at each iteration. A compiler can optimize this but just avoid it.
Also a problem is that you convert the string arguments of -a and -s into an int value with this because you use the conversion before checking the values of the arguments. Note that used in the right way (when the conversion is only done based on a value argument) we don't need the variable value at all.
You can simplify the code like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
int result = 0;
for (int i = 1; i < argc; i++) {
if ( strcmp(argv[i], "-a") == 0 && i + 1 < argc && strcmp("-s", argv[i+1]) && strcmp("-a", argv[i+1]) ) {
result += atoi(argv[i+1]);
i++; // We use the next argument already here, so go forward.
}
else if ( strcmp(argv[i], "-s") == 0 && i + 1 < argc && strcmp("-s", argv[i+1]) && strcmp("-a", argv[i+1]) ) {
result -= atoi(argv[i+1]);
i++; // We use the next argument already here, so go forward.
}
else {
result += atoi(argv[i]);
}
}
printf("%d\n", result);
return 0;
}
Execution
Your example:
./calculator -a 10 -s 5 10 25
40
My example:
./calculator 10 34 -a 6 -s 4 25 -a 19 5 -s 24
71
Have fun at proof if the calculation is correct. ;-)
Or just try it online.
The problem with your code is that argv[1] is only tested to be either -a or -s but there is no code that converts argv[1] to a number and adds it to the result.
You need to handle all 3 cases in the loop, i.e. case 1 "-a", case 2 "-s" and case 3 "a number".
This could be like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int result = 0;
int i = 1;
while (i < argc) {
if (strcmp(argv[i], "-a") == 0) {
// Case 1
++i; // Increment i to move to next argument
if (i == argc) break; // Check that there is a valid argument
int value = atoi(argv[i]);
result += value;
} else
if (strcmp(argv[i], "-s") == 0) {
// Case 2
++i;
if (i == argc) break;
int value = atoi(argv[i]);
result -= value;
} else {
// Case 3 Current argument is (expected to be) a number
int value = atoi(argv[i]);
result += value;
}
++i; // Move to next argument
}
printf("%d\n", result);
return 0;
}
The above code uses atoi like the code in the question. A down-side of atoi is that there is no input validation, i.e. it's not validated that the string is actually a number.
For better input validation consider using strtol instead of atoi.
Your program does not seem to implement a solution to the problem:
You should keep track of the current mode ie: adding or subtracting and handle each argument accordingly (resetting the mode after each number handled).
Your nested loop ignores the first of 2 arguments. It also ignores the argument if only one is provided.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int result = 0;
int mode = 1;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-a")) {
mode = 1;
} else
if (!strcmp(argv[i], "-s")) {
mode = -1;
} else {
char *p;
int value = strtol(argv[i], &p, 0);
if (p == argv[i] || *p != '\0') {
printf("invalid argument: %s\n", argv[i]);
} else {
result += mode * value;
}
mode = 1; // only subtract a single argument
}
}
printf("%d\n", result);
return 0;
}
Note that the above program detects invalid input but does not detect nor handle arithmetic overflow.
Related
error imageI tried to make a program that does calculation with multiple arguments.
Everything works as I intended except for last one in the picture i attached.
Every time I try to put more than 2 numbers in the command line, the error occurs.
The example of input is this : program1.exe 12 + 13 - 2 + 1
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int a, b, rst;
int i;
char opr;
if (argc > 100)
{
printf("Too many arguments!\n");
return 0;
}
else if (argc <= 1)
{
printf("There are no arguments!\n");
return 0;
}
a = atoi(argv[1]);
rst = a;
if (argc == 2)
{
a = atoi(argv[1]);
}
else if (argc % 2 != 0)
{
printf("Invalid fomula!\n");
exit(0);
}
else
{
for (i = 1; 2*i <= argc; i++)
{
b = atoi(argv[2 * i]);
opr = argv[2 * i - 1];
switch (opr)
{
case '+':rst = a + b;
break;
case '-':rst = a - b;
break;
}
rst = a;
}
}
printf("%d", rst);
return 0;
}
Running the code as is, with input set to: <program.exe> 2 + 5
a null pointer error occurs here:
for (i = 1; 2*i <= argc; i++)
{
b = atoi(argv[2 * i]);//Null pointer for i==2
opr = argv[2 * i - 1];
switch (opr)
because there is no argv[4]. This results in undefined behavior.
It is impossible to make corrections accurately without knowing what the program expects as input. Because you do not specify, my best guess is the program attempts to read a set of arguments from the command line, eg:
argv[0] argv[1] argv[2] argv[3]
<program>.exe 1 + 2
Then convert the values read into variables, and perform a math operation using two numerics and a math operator such as + or -.
Assuming this is the basic goal, the following example simplifies your existing code to perform these steps. Note corrections to the argument input count test, and lower down, the looping indexes:
#include <stdio.h>
#include <stdlib.h>
/// test using:
// prog.exe 2 + 3 3 - 4 6 + 7
//results are:
//result 0: 5
//result 1: -1
//result 2: 13
typedef struct {
int n1;
char opr;
int n2;
int result;
} CALC;
int main(int argc, char *argv[])
{
int i;
// test for correct number of input arguments
if((argc-1)%3 !=0)
{
printf("Wrong number of inputs.\n");
return 0;
}
// read in, and assign variables (use array of struct)
int max = (argc-1)/3; //guaranteed viable only after determining multiples are correct from above
//Get ALL input into array variables
CALC calc[max];
for (i=0;i<max;i++)
{
//convert inputs into usable variables
calc[i].n1 = atoi(argv[i*3+1]);
calc[i].opr = argv[i*3+2][0];
calc[i].n2 = atoi(argv[i*3+3]);
// perform calulations
switch(calc[i].opr) {
case '+':
printf("result %d: %d\n", i, calc[i].n1 + calc[i].n2);
break;
case '-':
printf("result %d: %d\n", i, calc[i].n1 - calc[i].n2);
break;
}
}
return 0;
}
Most error checking, and testing of function return values are left to you.
I've done this question on leetcode before but wanted to do it in C. Was wondering if anyone could let me know if there is a better way to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printBinaryLenthHelper(int currentLength, int maxLength, char accum[]) {
if (currentLength == maxLength) {
printf("%s\n", accum);
return;
}
accum[currentLength++] = '0';
printBinaryLenthHelper(currentLength, maxLength, accum);
accum[--currentLength] = '1';
printBinaryLenthHelper(++currentLength, maxLength, accum);
}
void printBinaryLength(int length) {
char accum[length + 1];
printBinaryLenthHelper(0, length, accum);
}
int main() {
printBinaryLength(20);
}
You can avoid recursion by simply iterating from 0 to 2^n -1. This range represents all the numbers with binary length n (assuming smaller numbers are padded with leading zeroes).
Code
#include <stdio.h>
void printBinary(int len) {
//This loop iterates from 0 to 2^len - 1
for(int i = 0; i < 1 << len; ++i) {
//This loop is to print the integer in its binary representation.
for(int j = len - 1; j >= 0; --j) {
// ((1<<j)&i) > 0 evaluates to 1 if the jth bit is set, 0 otherwise
printf("%d", ((1<<j)&i) > 0);
}
printf("\n");
}
}
int main(void) {
// your code goes here
printBinary(10);
return 0;
}
Output
0000000000
0000000001
0000000010
0000000011
0000000100
0000000101
0000000110
0000000111
0000001000
0000001001
0000001010
...
Tested here.
PS: If you do not understand what 1<<j and (1<<j)&j means, read about bitwise operators in C.
There is a problem in your function printBinaryLenthHelper: you do not null terminate the string before passing it to printf. It is also confusing to increment and decrement currentLength as a side effect, just pass the next value in the recursive call.
Here is a corrected version:
void printBinaryLenthHelper(int currentLength, int maxLength, char accum[]) {
if (currentLength == maxLength) {
accum[currentLength] = '\0';
printf("%s\n", accum);
return;
}
accum[currentLength] = '0';
printBinaryLenthHelper(currentLength + 1, maxLength, accum);
accum[currentLength] = '1';
printBinaryLenthHelper(currentLength + 1, maxLength, accum);
}
Note also that the name should be printBinaryLengthHelper.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <crypt.h>
int main(int argc, string argv[])
{
if(argc > 2){ printf("too many arguments\n"); return 51; }
if(argc < 2){ printf("too few arguments\n"); return 50; }
//if(strlen(argv[1]) > 4){ printf("Password is greater than 4 characters\n"); return 52; }
if(argc == 2) //make sure there are enough args
{
char hash_guess[] = "rofk";
//long long counter = 0;
//while(guess != argv[1]) //crypt(hash_guess, "50") != argv[1]) //while answer not correct
//{
for(int a = 65; a < 91; a++)
{
for(int b = 65; b < 91; b++)
{
for(int c = 65; c < 91; c++)
{
for(int d = 65; d < 91; d++)
{
for(int A = 0; A < 9; A = A + 5) //control if first is caps or not
{
for(int B = 1 ; B < 9 ; B = B + 5)//control if second is caps or not
{
for(int C = 2; C < 9; C = C + 5) //control if third is caps or not
{
for(int D = 3; D < 9; D = D + 5) //control if fourth is caps or not
{
hash_guess[0] = a;
hash_guess[1] = b;
hash_guess[2] = c;
hash_guess[3] = d;
hash_guess[A] = tolower(hash_guess[A]);
hash_guess[B] = tolower(hash_guess[B]);
hash_guess[C] = tolower(hash_guess[C]);
hash_guess[D] = tolower(hash_guess[D]);
printf("%s\n", hash_guess);
string cryptoguess = (crypt(hash_guess, "50"));
string input = argv[1];
if( cryptoguess == input ) { return 0; }
}
}
}
}
}
}
}
//}
//}
//string guess = crypt(hash_guess, "50");
//printf("%lli", counter);
}
}
}
I'm trying to make a program that goes through every 4 letter word, starting on aaaa and going to ZZZZ. I got that part done.
Part of the assignment is to encrypt that, and if the encryption matches an encrypted password, then you know you "hacked" their password. When I compare the encrypted password that I manually enter and the one that comes up by using the crypt function, they are the same, but in the debugger I see this for when it is encrypted by the computer:
"0x7ffff7dd9200 <_ufc_foobar+131200> "50k72iioeOiJU""
and the normal one that I enter shows
"0x7fffffffe34f "50k72iioeOiJU""
the same thing without the _ufc_foobar. Does anyone know why that is there and how I can get rid of it?
The weird junk you are seeing is visualization of offsets of memory addresses in your code which can be ignored.
In your code you are using string when GNU specifies char * is the result of the crypt function.
Therefore, you cannot compare the pointers to the char array using == but instead need to use strcmp C comparing pointers (with chars)
For crypt see: http://www.gnu.org/software/libc/manual/html_node/crypt.html
<_ufc_foobar+131200> isn't part of the string. It's your debugger attempting to figure out where the string came from, and assign a name to it. In this case, it's come up with a bogus result -- _ufc_foobar is the name of a function or variable somewhere else in the program, and your string happens to be stored 131,200 bytes (about 128 KB) after that in memory.
You can safely ignore this. Your strings are equal. They just happen to be stored in different parts of memory (which is normal).
I've tried this code but it doesn't seem to be working, how to break out of the nested loop ?
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[])
{
int i = 0, j = 0;
int different;
while (i <= strlen(s1) && different == 1) {
while (j <= strlen(s2)) {
if (s1[i] != s2[j]) {
different = 1;
} else {
different = 0;
}
j = j + 1;
}
i = i + 1;
}
return different;
}
You have to initialize different as it is undefined if not - this probably breaks your first while loop as different probably is a random number > 1.
strlen gives you the number of characters in the string excluding the null-character which terminates the string (see here). However, you do not only compare the characters of the two strings, but also the null-character, probably to implicitely check if the length of the strings is the same. While this should work, it is better to do this check explicitely by comparing the length of the strings first as it is less error-prone.
It isn't necessary to do a nested loop here if you compare the length of the strings first. Also, you now know the length of both strings, so this function can be change to use a for loop, which makes it even simpler.
A possible solution based on the points above:
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[]){
int i = 0;
int len_s1 = 0;
int len_s2 = 0;
int different = 0;
len_s1 = strlen(s1);
len_s2 = strlen(s2);
if (len_s1 == len_s2) {
for (i = 0 ; i < len_s1 ; i++) {
if (s1[i] != s2[i]) {
different = 1;
break;
}
}
else {
different = 1;
}
return different;
}
One more thing - do yourself and everyone else a favor and intend your code as it is extremely hard to read otherwise!
Your code is not optimized and you are not using a good approach for doing the task. I have modified the code and it will do the job with minimized complexity.
Here I assume that both the arrays are of same size as your problem shows
bool meme(char s1[], char s2[])
{
int i=0;
while(s1[i] != NULL && s2[i] != NULL)
{
if(s1[i] == s2[i])
return false;
i += 1;
}
return true;
}
When you call this function then declare a variable of type bool and store the returned value of this function in that variable.
For example :
bool check;
bool = meme(array 1 , array 2);
and then check if returned value is true, then both the arrays are totally different else not. You can do that by the below code :
if(check)
printf("Arrays are different");
else
printf("Arrays are not different");
You can also use int in place of bool if it suits you better but remember, whatever code you write, must be least complex. And think that if you are using int then also you are returning only 0 or 1; but int takes 2 bytes in 32-bit compiler and 4 bytes in 64-bit compiler, but bool takes only 1 byte and even 1 bit in some languages like pascal (if I am not wrong).
And don't get confused with return true; and return false;. True simply means 1 and false means 0. And a boolean type variable can store only binary number (1 or 0).
There is so much wrong with your code.
Why are you calling strlen() in while()? It will get executed every time till the loop doesn't exit and will cost on performance.
Also the variable different is not initialized with value 1, so how can you be so sure about the initial value of that variable?
I have tried to simplify your function still, there is scope for optimization:
int meme(char s1[], char s2[])
{
int i = 0;
int different;
int str1_len = strlen(s1);
int str2_len = strlen(s2);
if(str1_len > str2_len)
str1_len = str2_len;
do{
if(s1[i] == s2[i])
{
printf("Common\n");
different = 0;
}
else
{
different = 1;
}
i++;
}while(str1_len--);
return different;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define TAB_STOP 8
/* replaces tabs from input with the proper amount of blank spots */
int Detab()
{
int c, x;
int column;
x = column = 0;
while((c=getchar())!=EOF)
{
if(c == '\n') /* reseting counter if newline */
{
putchar(c);
return 1;
}
else if(c!='\t') /* column counts places to tab spot */
{
putchar(c);
column++;
if(column == TAB_STOP)
column = 0;
}
else /* tab */
{
for(x=0; x<TAB_STOP - column; x++)
putchar('_');
column = 0;
}
}
return 0;
}
#define MAX_ARGUMENTS 100
int main(int argc, char *argv[])
{
int i, val = 0;
int nums[MAX_ARGUMENTS];
int x = 0;
for(i = 1; i < argc; i++) {
while(isdigit(*argv[i])) {
val = val * 10 + *argv[i] - '0';
*++argv[i];
}
if(x > MAX_ARGUMENTS - 1)
return 0;
nums[x++] = val;
nums[x] = '\0';
val = 0;
}
while(Detab(nums));
printf("Press any key to continue.\n");
getchar();
return 0;
}
In main i put all the arguments(numbers) inside nums array and then pass it to detab. So now im interested what would be the smart way to edit detab so it works. I'm still trying to figure out for a working pseudocode but i dont really know.
The way i tought it should work is:
if arguments are 5, 8, 10 then a tab inside first 4 characters leads to position 5, in 5 - 7th char leads to pos 8 etc.
In case of a newline, the arguments start all over again from the begining.
The most common way is to have Detab accept a pointer (which points to an element in an array) and the length of that array:
int Detab(int* data, int len); // access data[0] through data[len - 1]
Call it like so:
void example() {
int array[] = {5, 8, 10};
Detab(array, 3);
// or:
Detab(array, sizeof array / sizeof *array); // second parameter evaluates to 3
// without using a magic constant
}
Here's some pseudocode for expanding tabs:
def expandtabs_in_line(line, tabstops, default, space):
result = ""
for c in line:
if c != "\t":
result += c
else:
for stop in tabstops:
if stop > len(result):
result += space * (stop - len(result))
break
else:
result += space * (default - (len(result) % default))
return result
def expandtabs(lines, tabstops=[], default=8):
for line in lines:
yield expandtabs_in_line(line, tabstops, default, " ")
Try it out at codepad.