Defining Command Line Arguments w/ functions - c

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.)

Related

How to generate non-repeating numbers in C?

my first post here.
I'm trying to write a program in C, which generates a random password made of numbers, letters and capitals. The problem is that characters in password must NOT be repeated. I tried a few ways to prevent that, but nothing seemed to work.
void createPassword() {
char password[LENGTH];
char nums[] = "0123456789";
char letters[] = "abcdefghijklmnopqrstuvwxyz";
char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int selector = rand() % 3; //random choice of character type
int i;
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
if(selector == 1) { //if selector == 1, add number to password etc.
password[i] = nums[rand() % 10];
printf("%c", password[i]);
selector = rand() % 3;
}
else if(selector == 2) {
password[i] = letters[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
else {
password[i] = caps[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
}}
I'll be glad if someone could tell me what to do next.
Picking a random index of an array is the same as picking the values of a shuffled array sequentially. I used Fisher–Yates shuffle Algorithm for shuffling of the array. After generating a shuffled array, just pick the index of the next character from the shuffled array, and use symbols[] to access the corresponding character from it. Also. I used srand(time(0)) to give a random seed for the random number generator. Include time.h for using time(0).
void createPassword() {
char password[LENGTH];
int total = 10+26+26;
char symbols[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
int ar[total];
for(i = 0; i < total; i++){
ar[i] = i;
}
srand(time(0));
for (i = total-1; i >= 1; i--){
// get random 0 <= temp <= i
int temp = rand() % (i+1);
// Swap ar[temp] and ar[i]
int temp2 = ar[i];
ar[i] = ar[temp];
ar[temp] = temp2;
}
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
password[i] = symbols[ar[i]];
printf("%c", password[i]);
}
}
That's not a big deal, random seeds are similar for several runs in C.
You may need to set the random seed to time(0) by adding something like this, first of your code:
srand(time(0));
You should import time.h too.
#include <time.h>
Besides if you want to make a password consisting numbers and alphabets at the same time you may need to move selector assignment into the loop.
An easy way to force random numbers with no repeating letters can be implemented by using an array of elements, that will play the role of a card deck.
Each time you get a card, you get it from the rest of the deck (there's a point that differentiates cards that have been already xtracted with cards that are still to be output) You select a random number between 0 to n-1 where n-1 is the number of cards left in the deck. Once extracted, you switch the card extracted with the first of the group that is still to be extracted, and advance the point one position behind it, so it becomes already extracted and is not selected again.
A sample implementation is shown below, in the function extract, which uses an array of cells to store the available objects to print (they can be anything, they are char in the given implementation to be able to produce what you want ---random strings with non repeating characters):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
typedef char cell;
/* cell is a type (the above definition allows to be generic)
* array is the array of cards still to be output, n is its size.
* which is the card we select from the array, so it must be in
* range 0..n-1. */
cell extract(cell *array, size_t n, int which)
{
if (which) {
/* exchange position n with position 0 */
cell temp = array[0];
array[0] = array[which];
array[which] = temp;
}
return array[0];
}
/* this is a simple main program to illustrate how to use the
* function above. */
int main(int argc, char **argv)
{
unsigned N = 10;
unsigned seed = 0;
/* we use an array, because we need to modify it. */
char alpha[1024] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int opt;
int show_seed = 0;
while ((opt = getopt(argc, argv, "n:s:a:S")) != EOF) {
switch (opt) {
case 'n': N = atoi(optarg); break;
case 's': seed = atoi(optarg); break;
case 'S': show_seed = 1; break;
case 'a': strncpy(alpha, optarg, sizeof alpha); break;
}
}
if (seed) srand(seed);
else {
sranddev();
srand(seed = (unsigned)rand());
if (show_seed) {
fprintf(stderr,
"seed = %u\n",
seed);
}
}
argc -= optind;
argv += optind;
int len;
cell *pos;
for (pos = alpha, len = strlen(alpha);
*pos && len && N--;
pos++, len--)
{
putchar(extract(pos, len, rand() % len));
}
puts(""); /* final \n */
}
The program's usage is:
deck [ -a string ][ -S ][ -s seed ][ -n N ]
where:
-a allows you to specify the string where characters will be taken from. Defaults to ABCDEF...XYZ
-S prints the seed used in the run, so you can specify it to initialize the random number generator.
-s specifies a seed from a previous run to generate the same sequence. Defaults to a random initialization based on sranddev() (FreeBSD)
-n specifies the number of characters to select from the string. Defaults to 10.
A sample run is:
$ deck -s 123456
UKWOACYZLI
$ deck -s 123456 -n 26
UKWOACYZLITPJHQESVGMRBXFDN
$ _
As you see no character is repeated.

While loops and arrays causing very odd behaviour...maybe a memory mixup

I'm tired of this tom-foolery occurring during runtime , although I'm sure we all are, when our programs screw up at runtime in the most obscure ways.
Getting to the point, the entire source code is a bit large to place here, but still <200 lines, so that's here . Use it if running the program, since the code I will post below is just functions, where I think the error lies.
Context : This is a sort of shift cipher with 8 different shifts taken using an 8 digit pin.
The issue is strange. Basically, the encrypt() function works correctly always -I've matched it by doing the algorithm for myself on paper ; for example, ABC is correctly encoded to 3c 45 46 -6f when the Pin is 12345678.
The strange issues are with the decrypt() function.
When the program is run for the first time, trying to run decrypt() on a valid ciphertext-pin pair always returns nothing except a /n (newline) . When tried with a different valid pin-ciphertext pair, after a successful run of encrypt() is done first, the decrypt() function just returns either the same message which was just encrypted or some other random output from the previously encoded message.
Without further ado, the legendarily screwed up decrypt function which I have rebuilt thrice now -
void decrypt()
{
printf("\n");
int *digits = pin(); int d[8];
getchar();
for (int i=0;i<8;i++)
d[i] = *(digits + i); //puts each digit in a local array.
printf("\nEnter encoded message -\n\n");
getchar();
int j; char ch, msg[3002];
for(int i=0; i < 3000;i++)
{
scanf("%x",&j);
if(j==-111){
msg[i] = '\0'; //terminates string with \0
break;
}
else{
if(ctln(i)==1)
ch = j - d[2];
else if(fib(i)==1)
ch = j + d[4];
else if(luc(i)==1)
ch = j - d[0];
else if(pent(i)==1)
ch = j + d[6];
else if(hex(i)==1)
ch = j - d[3];
else if(prm(i)==1)
ch = j + d[7];
else {
if(i%2 == 0)
ch = j - d[1];
else
ch = j + d[5];
msg[i] = ch;
}
}
}
printf("\nDecrypted message -\n\n");
puts(msg);
}
For context, as well as finding the culprits here, do make sure to read the full code here , with the pin() returning a pointer to a static int array holding all 8 digits , as well as the ctln() , fib(), luc(), pent(), hex(), prm() [ which check if position value i of char in message is a part of Catalan, Fibonacci , Lucas, Pentagon, Hexagon, Prime number series. More here.
Edit 1
I have already tried keeping different variable names, and some other things I can't fully recall. Also, because it is very relevant, below is the pin() function:
int *pin()
{
int num,q=0; static int pins[8];
printf("Enter 8-digit PIN : ");
scanf("%d", &num);
for(register int i = 10000000 ; i >= 1 ; i = (i/10)) // i is position of digit.
{
int d = ((num - (num % i)) / i); // d stores 'digit' ( divides quotient of (num % i) by i)
pins[q] = d; q++;
num = (num - ( d * i ));
}
return pins ; // pointer to static array storing digits of PIN
}
Edit 2
I had wrongly assigned pins[6] rather than pins[8] in the original code, I have corrected it but am still facing the same errors.
Edit 3
After correcting the mistake pointed out by MikeCAT, it now ignores the first character when deciphering.
Edit 4
The getchar() before scanf() was to blame, removing it fixes the last issue too. Thanks #MikeCAT !
In your decrypt() function, msg[i] = ch; is executed only if none of the functions ctln, fib, luc, pent, hex, prm returned 1.
Therefore, uninitialized value of non-static local variable msg, which is indeterminate, may be used for printing and undefined behavior may be invoked.
The part
msg[i] = ch;
}
should be
}
msg[i] = ch;
as it is done in encrypt() function.

Why does the number get ignored?

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.

algorithm for finding unique any size combination of numbers in c [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I need a clean c code to find out combination of numbers.
Any number of numbers and any size of combination.
Such as for {1,2,3}
output should be {1,2,3,12,13,23,123}, note 23 and 32 as same.
Is there any clean c program for that ?
Best regards,
There are many ways of doing this. Here's a way using bit manipulation.
Let the given set be a.
The code for this is pretty small. Understand the following and you will understand how that tiny snippet of code works.
The first thing you have to realize here is that you are finding the (2n - 1) subset of the given set.
Any set has 2n subsets and here, you have excluded the null set. Hence (2n - 1)
Now, to generate these subsets we need an algorithm.
Observe the following:
001 --- 1
010 --- 2
011 --- 3
100 --- 4
101 --- 5
110 --- 6
111 --- 7
The left digits constitute the binary representation of the right decimal numbers.
If we write out for binary numbers with 4 digits, there would be 15 combinations. Notice that I am excluding the combination where all digits are zero in the above example.
In general, for n-bit binary numbers, there are (2n - 1) different combinations of the digits. We can use this to generate the subsets, in a very simple fashion.
For every element in the set, you are allowed to:
Choose the element for the current subset.
Don't choose that element for the current subset.
Leave out the situation where you choose none.
(Hence, there are (2n - 1) subsets)
Now, I say do the following:
for i in [1,2^n - 1]:
Let b = binary representation of i.
for every jth bit in b:
if the jth bit is set:
print a[j]
print a newline character.
Here is the C code:
// include your headers
int isJthBitSet(int i,int j)
{
// returns 1 if jth bit is set in the binary representation of i.
return (i & (1 << j));
}
int main()
{
int n = 3; // The size of the set for example.
int a[] = {1,2,3}; // the given set, for example.
for(int i = 1; i < (1 << n); i++) // i is from 1...2^n - 1
{
for(int j = 0; j < n; j++) // for every jth bit in the n-bit representation of i
{
if(isJthBitSet(i,j)) // if the bit is set
printf("%d ", a[j]); // print the corresponding element
}
printf("\n");
}
return 0;
}
And that would be pretty much it.
While I normally frown upon showing complete solutions, based on a few relatively recent similar questions and their answers, it seems that some examples of how to solve these types of combinatorics problems are warranted.
An easy way to construct all unique sets with k elements out of n elements, is to use k nested loops, where the loop indexes are always in increasing order. For example, to print all unique 3 char triplets, from a set of N chars, you could use
const char all[N] = ...;
char set[4];
size_t i, j, k;
set[3] = '\0'; /* End of string mark */
for (i = 0; i < N-2; i++) {
set[0] = all[i];
for (j = i+1; j < N-1; j++) {
set[1] = all[j];
for (k = j+1; k < N; k++) {
set[2] = all[k];
puts(set);
}
}
}
Now, the OP wants all unique subsets with up to k elements out of a set of n elements, which means we need cannot use nested loops as above (since we don't know the maximum k). Explicitly, anyway. Instead, we need to think of how to rewrite that.
To get a better grip on the construction, let's look at say the three-out-of-five case. The ten result sets are
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
There is clear order, and clear logic: increase the rightmost, unless it would become too large. Then, find the next index to the left that we can increment without going over (keeping enough elements for those on its right side). If we cannot increment even the leftmost without going over, we have produced all sets. (If you think about it, this is also quite a straightforward implementation of variably-nested loops.) After incrementing, set the elements to the right in ascending order.
In most cases, we'd like some sort of structure or object that keep tracks of the state and the current subset, with functions to initialize, free, and to switch to the next subset. Here is one possibility:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
typedef struct {
char *buffer; /* Symbol buffer */
size_t length; /* Number of symbols to choose */
size_t *index; /* Index of each symbol */
char *symbol; /* Array of symbols */
size_t symbols; /* Number of symbols to choose from */
} generator;
void generator_free(generator *const g)
{
if (g) {
free(g->buffer);
free(g->index);
free(g->symbol);
g->buffer = NULL;
g->length = 0;
g->index = NULL;
g->symbol = NULL;
g->symbols = 0;
}
}
const char *generator_current(generator *const g, const char *const none)
{
return (g && g->buffer) ? g->buffer : none;
}
int generator_init(generator *const g, const char *const symbol, const size_t choose)
{
const size_t symbols = (symbol) ? strlen(symbol) : 0;
size_t i;
if (!g || symbols < 1 || choose < 1 || choose > symbols)
return EINVAL;
g->buffer = malloc(choose + 1);
g->index = malloc((choose + 1) * sizeof g->index[0]);
g->symbol = malloc(symbols + 1);
if (!g->buffer || !g->index || !g->symbol) {
free(g->buffer);
free(g->index);
free(g->symbol);
g->buffer = NULL;
g->length = 0;
g->index = NULL;
g->symbol = NULL;
g->symbols = 0;
return ENOMEM;
}
memcpy(g->buffer, symbol, choose);
g->buffer[choose] = '\0';
g->length = choose;
for (i = 0; i < choose; i++)
g->index[i] = i;
g->index[choose] = symbols;
memcpy(g->symbol, symbol, symbols);
g->symbol[symbols] = '\0';
g->symbols = symbols;
return 0;
}
int generator_next(generator *const g)
{
size_t i;
if (!g || !g->buffer || g->length < 1 || !g->index)
return EINVAL;
if (g->index[0] >= g->symbols - g->length)
return ENOENT;
if (++g->index[g->length - 1] >= g->symbols) {
i = g->length - 1;
while (i > 0 && g->index[i] + 1 >= g->symbols - i)
i--;
g->index[i]++;
if (!i && g->index[0] > g->symbols - g->length) {
memset(g->buffer, '\0', g->length + 1);
return ENOENT;
}
while (i++ < g->length)
g->index[i] = g->index[i-1] + 1;
}
for (i = 0; i < g->length; i++)
g->buffer[i] = g->symbol[g->index[i]];
g->buffer[g->length] = '\0';
return 0;
}
generator_current() provides the current set (as a string). Instead of returning NULL when there is no valid set, it returns the string you specify as the second parameter. (It's just for convenience, no real reason behind this.)
generator_free() discards the generator, generator_init() initializes a new generator, and generator_next() advances the generator to the next subset.
Note that generator_init() also initializes the first subset; the one where the elements are chosen consecutively. (Although the ->symbol is only a character array containing all characters in the overall set, the function appends an end-of-string mark, so you can treat it as a string, too.)
The first if clause in generator_next() just makes sure the generator is initialized; it's just a sanity check. The second one checks if the generator is complete.
The third if clause in generator_next() increments the rightmost index, changing the last element in the subset. If it runs out of valid elements, the while loop searches for the index i for an index that can be incremented without running out of elements. Note that because the indexes are in ascending order (that ensures unique subsets), this must remember to account for the elements needed for the rest of the position.
If i becomes zero and overflows, there are no more subsets, and the ->buffer member is cleared to an empty string (just in case).
Otherwise, the second while loop fills in the indexes to the right of i with consecutive values. (See the above example for three-out-of-five, the case where the first element changes from 1 to 2, for illustration of why this is needed.)
Finally, the for loop is used to copy the elements from the ->symbol array, according to the indexes, to ->buffer.
For the askers case, the size of the subsets varies, so to generate all subsets, a loop is needed. For example:
generator g;
size_t i;
for (i = 1; i <= 2; i++) {
if (generator_init(&g, "123", i)) {
fprintf(stderr, "generator_init() failed!\n");
exit(EXIT_FAILURE);
}
do {
/* Print the set and a newline */
puts(generator_current(&g, ""));
} while (!generator_next(&g));
generator_free(&g);
}
For testing, I used the following helper function and main():
int parse_size(const char *s, size_t *const dst)
{
const char *endptr = NULL;
unsigned long value;
size_t result;
int skip = -1;
if (!s || !*s)
return EINVAL;
errno = 0;
value = strtoul(s, (char **)&endptr, 0);
if (errno)
return errno;
if (!endptr || endptr == s)
return EEXIST;
(void)sscanf(endptr, " %n", &skip);
if (skip > 0)
endptr += skip;
if (*endptr)
return EEXIST;
result = (size_t)value;
if ((unsigned long)result != value)
return EDOM;
if (dst)
*dst = result;
return 0;
}
int main(int argc, char *argv[])
{
generator g;
size_t symbols, length, len;
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s DIGITS LENGTH\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This will print each unique set of LENGTH characters from DIGITS,\n");
fprintf(stderr, "one set per line.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
symbols = (argv[1]) ? strlen(argv[1]) : 0;
if (symbols < 1) {
fprintf(stderr, "No DIGITS specified.\n");
return EXIT_FAILURE;
}
if (parse_size(argv[2], &length) || length < 1 || length > symbols) {
fprintf(stderr, "%s: Invalid LENGTH.\n", argv[2]);
return EXIT_FAILURE;
}
for (len = 1; len <= length; len++) {
if (generator_init(&g, argv[1], len)) {
fprintf(stderr, "Generator initialization failed.\n");
return EXIT_FAILURE;
}
do {
puts(generator_current(&g, ""));
} while (!generator_next(&g));
generator_free(&g);
}
return EXIT_SUCCESS;
}
In Linux, I prefer to compile the above using gcc -Wall -Wextra -ansi -pedantic -O2 main.c -o example. The original question asked for
./example 123 2
which outputs
1
2
3
12
13
23
A larger example is much more interesting. For example,
./example 12345 3
lists all one, two, and three-digit sets from the set of first five digits. The output is
1
2
3
4
5
12
13
14
15
23
24
25
34
35
45
123
124
125
134
135
145
234
235
245
345
Questions?

extracting a char from a char.Eg 1 from 123

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).

Resources