extracting a char from a char.Eg 1 from 123 - c

In this program convert.c, I am trying to convert a given number of any base to base 10. The command is given as convert .todecimal is supposed to do that. The code below has errors of course but I am not sure how to make it work. For eg,the number in argv[3]is 123 in base 9. The equation is supposed to work like this :(1 x 9^2) + (2 x 9^1) + (3 x 9^0) = (102)10.where the variables are (n x argv[3]^i) + (n+1 * argv[3]^i-1)....How do i get a char of 123 when 123 itself a char? Any help is appreciated.
#include<stdio.h>
#include<math.h>
int todecimal();
main(int argc, char *argv[])
{
int s = 0;
int i = 0;
int n = 1;
if (argc < 4) {
printf("Usage: convert <basefrom> <baseto> <number>\n");
}
printf("to decimal prints %d" todecimal());
}
int todecimal() {
if (argv[3] > 0) {
if ((getchar(argv[3]) != NULL)) {
i = i + 1;
}
while (i >= 0) {
s = s + (n * (pow(argv[3],i)));
n = n + 1;
i = i - 1;
}
return s;
}
}

There is a difference between char and char*. The latter is a pointer to char, also used as a string (a sequence of chars). So, wherever you can have more than one char, you use a pointer (to the first one) instead - this is your argv[3].
So, to get one char from a sequence of chars, you apply square brackets:
argv[3] - is the whole string, let's pretend it's "192" to reduce confusion
argv[3][0] - is the first char, '1'
argv[3][1] - is the second char, '9'
argv[3][2] - is the third char, '2'
In your case, you need argv[3][i]. But you have to fix your other bugs too (there are many, as other people noted).

Related

Inline sprintf() for defining string as num in C?

So a bit ago I was warming up and doing some very simple challenges. I came across one on edabit where you need to make a function to add the digits of a number and tell if the resulting number is "Oddish" or "Evenish"
(ie oddishOrEvenish(12) -> "Oddish" because 1 + 2 = 3 and 3 is odd)
so I solved it with some simple code
# include <stdio.h>
# include <stdlib.h>
char* odOrEv(int num);
int main(int argc, char* argv[]) {
printf("%s", odOrEv(12));
}
char* odOrEv(int num) {
char* strnum = (char*) malloc(11);
char* tempchar = (char*) malloc(2); // ik i can declare on one line but this is neater
int total = 0;
sprintf(strnum, "%d", num);
for (int i = 0; i < sizeof strnum; i++) {
tempchar[0] = strnum[i];
total += (int) strtol(tempchar, (char**) NULL, 10);
}
if (total % 2 == 0) return "Evenish";
return "Oddish";
}
and it worked first try! Pretty rudimentary but I did it. i then thought hey this is fun howabout I make it better, so I got it down to
# include "includes.h"
char* odOrEv(int num);
int main(int argc, char* argv[]) {
printf("%s", odOrEv(13));
}
char* odOrEv(int num) {
char* strnum = (char*) malloc(11);
int total = 0;
sprintf(strnum, "%d", num);
while (*strnum) total += (int) *strnum++;
return total % 2 == 0 ? "Evenish" : "Oddish";
}
just 5 lines for the function. Since I'm so pedantic though, I hate that I have to define strnum on a different line than declaring it since I use sprintf. I've tried searching, but I couldn't find any functions to convert int to string that I could use while declaring the string (e.x. char* strnum = int2str(num);). So is there any way to cut off that one line?
srry if this was too big just tried to explain everything
P.S. don't tell to use atoi() or stoi or any of those since they bad (big reason long to eplain) also I'd prefer if I didn't have to include any more directories but it's fine if I do
EDIT: forgot quote added it
To be honest it the one of the weirdest functions I have ever seen in my life.
You do not need strings, dynamic allocations and monster functions like sprintf or strtol.
char* odOrEv(int num)
{
int sum = 0;
while(num)
{
sum += num % 10;
num /= 10;
}
return sum % 2 == 0 ? "Evenish" : "Oddish";
}
You don't actually have to add the digits. The sum of even digits is always even, so you can ignore them. The sum of an odd number of odd digits is odd, the sum of an even number of odd digits is even. So just loop through the digits, alternating between oddish and evenish every time you see an odd digit.
You can loop through the digits by dividing the number by 10 and then checking whether the number is odd or even.
char *OddorEven(int num) {
int isOdd = 0;
while (num != 0) {
if (num % 2 != 0) {
isOdd = !isOdd;
}
num /= 10;
}
return isOdd ? "Oddish" : "Evenish";
}

C Extract Infix (char array) and cast to int

Given a string/char array e.g :
99+(88-77)*(66/(55-44)+33)
How do I extract the numbers and operators?
I would like to store them into two stacks a and b each containing number and operators only.
I am not sure on the logic, I was thinking of scanning each char in the char array, adding the char (number) into another char, until it meets an operator. Then I go to the char(number) and concatenate the string.
Is there a better way to do this, preferabbly without external libraries?
As pointed out in comments, you can try using strtol for scanning integers from input string. I tried the suggested approach and it seemed to work for me for the provided test case. I haven't tested this for corner cases, but this should give you better idea of what users in comments are saying:
int main() {
char input[30] = "99+(88-77)*(66/(55-44)+33)";
// Initialize Stack Indices
operandStackIndex = 0;
operatorStackIndex = 0;
// Our markers for strtol()
char *pStart = input;
char *pEnd;
long ret;
while ((ret = convertStringToLong(pStart, &pEnd, 10)) > 0) {
operandStack[operandStackIndex++] = ret;
pStart = pEnd;
while (isOperator(*pStart)) { // Check whether character it '+','-','/','(',')','*'..
operatorStack[operatorStackIndex++] = *pStart;
pStart++;
}
}
printf("Operand Stack:\n");
for (int i = operandStackIndex - 1; i >= 0; i--)
printf("%d\n", operandStack[i]);
printf("Operator Stack:\n");
for (int i = operatorStackIndex - 1; i >= 0; i--)
printf("%c\n", operatorStack[i]);
}
Here is simple implementation for convertStringToLong method(alternative to strtol):
long convertStringToLong(char* pStart, char** pEnd, int base) {
long num = 0;
while (isDigit(*pStart)) {
num = num * base + (*pStart - '0');
pStart++;
}
*pEnd = pStart;
return num;
}
When I ran this, I was able to see expected output:
Operand Stack:
33
44
55
66
77
88
99
Operator Stack:
)
+
)
-
(
/
(
*
)
-
(
+

Print a Char Array of Integers in C

For class, I am required to create a function that converts an Integer into it's corresponding Binary number. However, I am forced to use the given main and parameters for the to_binary function. The whole problem requires me to print out the 32 bit binary number, but to break it up, I am just trying to print out the Char Array, that I thought I filled with Integers (perhaps the issue). When I do compile, I receive just a blank line (from the \n) and I am wondering how I can fix this. All I want to do is to be able to print the binary number for 5 ("101") yet I can't seem to do it with my professor's restrictions. Remember: I cannot change the arguments in to_binary or the main, only the body of to_binary. Any help would be greatly appreciated.
#include<stdio.h>
void to_binary(int x, char c[]) {
int j = 0;
while (x != 0) {
c[j] x = x % 2;
j++;
}
c[33] = '\0';
}
int main() {
int i = 5;
char b[33];
to_binary(i,b);
printf("%s\n", b);
}
This is the answer to your question.
void to_binary(int x, char c[]) {
int i =0;
int j;
while(x) {
/* The operation results binary in reverse order.
* so right-shift the entire array and add new value in left side*/
for(j = i; j > 0; j--) {
c[j] = c[j-1];
}
c[0] = (x%2) + '0';
x = x/2;
i++;
}
c[i]=0;
}
the problem is in the code below:
while (x != 0) {
c[j] = x % 2; // origin: c[j] x = x % 2; a typo?
j++;
}
the result of x % 2 is a integer, but you assigned it to a character c[j] —— integer 1 is not equal to character '1'.
If you want to convert a integer(0-9) to a character form, for example: integer 7 to character '7', you can do this:
int integer = 7;
char ch = '0' + integer;
One of the previous answers has already discussed the issue with c[j] x = x % 2; and the lack of proper character conversion. That being said, I'll instead be pointing out a different issue. Note that this isn't a specific solution to your problem, rather, consider it to be a recommendation.
Hard-coding the placement of the null-terminator is not a good idea. In fact, it can result in some undesired behavior. Imagine I create an automatic char array of length 5. In memory, it might look something like this:
Values = _ _ _ _ _
Index = 0 1 2 3 4
If I were to populate the first three indexes with '1', '0', and '1', the array might look like so:
Values = 1 0 1 _ _
Index = 0 1 2 3 4
Let's say I set index 4 to contain the null-terminator. The array now looks like so:
Values = 1 0 1 _ \0
Index = 0 1 2 3 4
Notice how index three is an open slot? This is bad. In C/C++ automatic arrays contain garbage values by default. Furthermore, strings are usually printed by iterating from character to character until a null-terminator is encountered.
If the array were to look like it does in the previous example, printing it would yield a weird result. It would print 1, 0, 1, followed by an odd garbage value.
The solution is to set the null-terminator directly after the string ends. In this case, you want your array to look like this:
Values = 1 0 1 \0 _
Index = 0 1 2 3 4
The value of index 4 is irrelevant, as the print function will terminate upon reading index 3.
Here's a code example for reference:
#include <stdio.h>
int main() {
const size_t length = 4;
char binary[length];
size_t i = 0;
while (i < length - 1) {
char c = getchar();
if (c == '0' || c == '1')
binary[i++] = c;
}
binary[i] = '\0';
puts(binary);
return 0;
}
#include<stdio.h>
int binary(int x)
{
int y,i,b,a[100];
if(x<16)
{
if(x%2==1)
a[3]=1;
if(x/2==1||x/2==3 || x/2==5 || x/2==7)
a[2]=1;
if(x>4 && x<8)
a[1]=1;
else if(x>12 && x<16)
a[1]=1;
if(x>=8)
a[0]=1;
}
for(i=0;i<4;i++)
printf("\t%d",a[i]);
printf("\n");
}
int main()
{
int c;
printf("Enter the decimal number (less than 16 ):\n");
scanf("%d",&c);
binary(c);
}
this code might help it will simply convert the decimal number less than 16 into the 4 digit binary number.if it contains any error than let me know

Defining Command Line Arguments w/ functions

The following code:
#include<stdio.h>
void main(int argc, char * argv[]) {
int i, n, sum = 0;
if (argc == 1) {
printf("You have forgot to type numbers.");
exit(1);
}
printf("The sum is: ");
///for (i = 1; i < argc; i++)
///sum = sum + atoi(argv[i]);
for(i = 0; i < argc; i++)
{
n = atoi(argv[i]);
sum += n;
}
printf("%d", sum);
}
gives me the sum in the command line, so for example if at the prompt I type, "program.exe 23 23 32", the output will be "The sum is: 68".
I would like to separate the sum logic so that it's its very own function, and then at the prompt I would like to be able to type, "program.exe -sum 23 23 32" to get the same result.
I found this and this. The latter contained some useful code, doing almost exactly what you want. Their example requires knowing how many arguments are being taken (the for loop in the sum function contains i < 5), but there could be a way of working around that.
man 3 stdarg should be helpful aswell.
It seems to me that you don't really need the - in front of sum; the first argument should be a simple string:
program.exe sum 1 3 5 9
Whether you keep the dash or not, you can simply arrange to pass a pointer to the remainder of the argument list to a function which expects that:
int sum(int numc, char **numv)
which returns the sum of the numc numbers represented as strings in the number vector numv. You can call that easily enough:
int rv = sum(argc - 2, argv + 2);
after you've established that sum is the function to call. And you can have a collection of such functions.
If you've encountered function pointers, you could create yourself an array of names (that the user will type on the command line) and function pointers (which point to the corresponding function). Then you simply have to look up the name the user typed in the array and call the appropriate function. That's probably still for the future for you, though.
In a lot of C code, we take shortcuts to make parsing easier. For example, let's say we know that we only have 2 choices of operator: sum or product. We then know that the first argument must be either -sum or -product. We can simplify the parsing by just checking for - followed by either s or p.
As for abstracting the actual operator, in this case it's probably more efficient to just check which operator was chosen on the command line, and then either apply += or *= based on that.
Here is some working code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
int n;
int result;
int i = 1;
char operator;
// parse -sum or -product
if (argv[i] && argv[i][0] == '-') {
// we take a shortcut and just look at the first letter
char firstLetter = argv[i][1];
if (firstLetter == 's') {
// using sum
operator = '+';
result = 0; // additive identity
}
else if (firstLetter == 'p') {
// using product
operator = '*';
result = 1; // multiplicative identity;
}
else {
printf("Unknown option: %s\n", argv[i]);
exit(1);
}
// move on to the next argument
i++;
}
else {
printf("Please specify an operation (-sum or -product)\n");
exit(1);
}
if (!argv[i]) {
printf("You have forgot to type numbers.\n");
exit(1);
}
for(; argv[i]; i++) {
n = atoi(argv[i]);
if (operator == '+') {
result += n;
}
else { // if (operator == '*')
result *= n;
}
}
printf("The result is: %d\n", result);
return 0;
}
Notice that the initial value of result is different depending on which operation was chosen.
Rather than using argc, the code above takes advantage of the fact that the argv array is null-terminated. In other words, if you had 3 arguments (or argc=4), then argv[3] will be NULL (which is equivalent to 0 or false).
Note that if you turn on optimizations, then any decent C compiler will move the test outside the loop, so it only actually checks which operator was chosen once. (This is easily verifiable by looking at the produced assembly code.)

I have no idea why I'm getting the errors I'm getting

Here is my code:
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <math.h> // this means I also need -lm at the execution of my code
int main(int argc, char *argv[])
{
if(argc != 2)
return 1;
const char salt[] = {argv[1][13], argv[1][12]}; // the value of salt is the first two chars in string argv[1], and the length of the hash is always 13
// This was const char key[9] and accounted for 8 of the errors
char key[9]; // create array of size 9 since one of the values is the null char
long long int i = 32; // initialize the incrementing variable at the lowest value printable ASCII character; long long because it's going to reach very high numbers
int j = (((i - 32))/95); // digit for key 1
int k = ((i - 32)/pow(95,2)); // digit for key 2
int l = ((i - 32)/pow(95,3)); // digit for key 3
int m = ((i - 32)/pow(95,4)); // digit for key 4
int n = ((i - 32)/pow(95,5)); // digit for key 5
int o = ((i - 32)/pow(95,6)); // digit for key 6
int p = ((i - 32)/pow(95,7)); // digit for key 7
while(i < pow(95,8) + pow(95,7) + pow(95,6) + pow(95,5) + pow(95,4) + pow(95,3) + pow(95,2) + 95) // this is inefficient but goes through every combination & string length
{
key[0] = ((i - 32) % 95) + 32;
key[1] = (j % 95) + 32;
key[3] = (k % 95) + 32;
key[4] = (l % 95) + 32;
key[5] = (m % 95) + 32;
key[6] = (n % 95) + 32;
key[7] = (o % 95) + 32;
key[8] = (p % 95) + 32;
if(char *crypt_r(const char *key, const char *salt, struct crypt_data *data) == argv[1]) // compare the hash of the current key string to the inputted hash
{
printf("%s\n", key);
return 0; //print password and exit
}
else // if the hashes don't match, then increment and try again
{
i++;
}
}
}
The point of the problem is to receive any hashed password that's been hashed using C's DES-based crypt function and use brute force to figure it out.
The problem is that when I try to compile, I get 9 errors. I'm using
clang -o crack crack.c -lcrypt -lm
Eight of them are from key[] =something, and they say that the "read only variable is not assignable".
The last one has an issue with the "if" statement at the end with the char in it, and it puts an arrow below char and says "expected expression". I've spent hours on this code, and I'd really appreciate some help with it.
Note: I am a student, and so it's much more helpful for explanations instead of "here you go I fixed your code". It's also against the rules for this assignment, and I will be linking the post to my assignment since the course mandates I recognize any additional help I received outside of the course's teaching fellows and instructive materials.
EDIT: I changed the key[] and made it not constant, which fixed 8 of the errors. The last one with "expected expression" remains.
Regarding this line:
if(char *crypt_r(const char *key, const char *salt, struct crypt_data *data) == argv[1]) // compare the hash of the current key string to the inputted hash
It looks like you copied the declaration for crypt_r instead of calling the function. The difference is that the declaration tells you what the function is, and when you call it, you need to fill everything in.
For example, if you have:
char* key;
char* salt;
struct crypt_data* data;
// initialize all of those
Then you would call it like:
char* result = crypt_r(key, salt, data);
In general, if you have a function in the form:
some_type function_name(another_type parameter_name);
Then the function returns a some_type and expects an another_type as the first parameter. You don't need to redeclare the whole thing, you just need to give it the two things it wants:
another_type x = whatever;
some_type result = function_name(x);

Resources