c command line arguments - c

#include <stdio.h>
#include <string.h>
int convert(char *str)
{
int i, number = 0;
for (i = 0; str[i] != '\0'; ++i) {
number = number * 10 + str[i] - '0';
}
return number;
}
int main(int argc, char *argv[])
{
int j;
int c = convert(argv[2]);
if (argc == 3) {
for (j = 0; j < c; j++) {
printf("Hello, %s!\n", argv[1]);
}
} else if (argc < 3) {
printf("Not Enough Arguments\n");
} else if (argc > 3) {
printf("Too Many Arguments\n");
}
return 0;
}
getting segmentation fault when giving less then 3 arguments.
on giving less than 3 arguments it should print "not enough arguments" but it gives error segmentation fault.
input:./a raju
expected output: not enough arguments

int c = convert(argv[2]);
When argc is 2, argv[2] will be NULL. What do you expect this line of code will do, as it's executed first thing when the program runs?
Refactoring so that the conditionals below it form a guard against that condition, here's something closer to what you probably intended:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int convert(char *str)
{
int i, number = 0;
for (i = 0; str[i] != '\0'; ++i) {
number = number * 10 + str[i] - '0';
}
return number;
}
int main(int argc, char *argv[])
{
if (argc != 3) {
printf( argc < 3 ? "Not Enough Arguments\n"
/*argc > 3*/ : "Too Many Arguments\n" );
exit(EXIT_FAILURE);
}
int c = convert(argv[2]);
for (int j = 0; j < c; j++) {
printf("Hello, %s!\n", argv[1]);
}
return 0;
}
P.S. As argv[0] is typically the program name rather than an argument, argv[1] and argv[2] will be your arguments, argv[3] will be NULL and if you count them you'll count two arguments, not three; expect argc == 4 when three arguments are given.

You may be interested in getopt.h library. It handles all the standard features of command line arguments.

Related

CS50 - Problem Set 2 - encountering "segmentation fault (core dumped)"

My program seems to be working fine and it does as intended, it takes command line arguments and "rotates" the inputted string from the prompt depending on the inputted command line argument. However, if I run my code without any arguments like: ./caesar it doesn't work, it says "segmentation fault (core dumped)" but if i run it like this ./caesar 1 or any other number, it works as intended.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int only_digits(string n);
char rotate(char i, int n);
int main(int argc, string argv[])
{
if(only_digits(argv[1]) && argc == 2) {
string plaintext = get_string("plaintext: ");
printf("ciphertext: ");
int k = atoi(argv[1]); // converts string n to k
for (int i = 0, l = strlen(plaintext); i < l; i++)
{
printf("%c", rotate(plaintext[i], k));
}
printf("\n");
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
int only_digits(string n) // function that returns 1 or 0 depending if given string is only digits
{
int state;
for(int i = 0, l = strlen(n); i < l; i++)
{
if (isdigit(n[i])) // checks if characters in string is a digit from 1 to 9
{
state = 1;
}
else
{
state = 0;
break;
}
}
return state;
}
char rotate(char c, int n)
{
char rotated_char = c;
if (isupper(c))
{
int a_index = c - 'A';
int c_cipher = (a_index + n) % 26;
rotated_char = c_cipher + 'A';
}
else if (islower(c))
{
int a_index = c - 'a';
int c_cipher = (a_index + n) % 26;
rotated_char = c_cipher + 'a';
}
return rotated_char;
}```
The quickest and easiest fix is to replace:
if(only_digits(argv[1]) && argc == 2)
With:
if(argc == 2 && only_digits(argv[1]))
Just swap the two sub-expressions around. When argc is 1 (ie, no arguments), argv[1] is NULL, and only_digits() cannot handle that - strlen(NULL) is incorrect.
However, if we do argc == 2 first, short-circuit evaluation rules say that since FALSE && anything is always FALSE, we don't need to bother evaluating only_digits(), so the code is never called and thus the crash is avoided.
You've got two good answers already.
My suggestion is to consider both the user and those programmers who will revise your code. Inform the user of the command line problem and don't 'hide' the 'fail' process at the bottom... If the processing is to stop, show that at the top (and you can save one level of indent, too!)
int main( int argc, string argv[] )
{
if( argc != 2 )
{
printf("Usage: ./caesar key [where key is all numeric]\n");
return 1;
}
if( !only_digits( argv[1] ) )
{
printf( "Key must be an integer value\n");
return 1;
}
int k = atoi( argv[1] ); // converts string n to k
string plaintext = get_string( "plaintext: " );
printf( "ciphertext: " );
for( int i = 0, l = strlen( plaintext ); i < l; i++ )
{
printf( "%c", rotate( plaintext[i], k ) );
}
printf("\n");
return 0;
}

How can I generate a list of all possible password combinations with argv?

I am a beginner so if I miss something vital to the code please forgive me haha. I am making a program which gets input from the console that says how many characters are going to be used, the characters (single letters), and then how long you want the password to be. I feel like I am pretty close, but every time I run the program, it seems to generate a random pattern of letters and I can't follow it.
Here is my code, including the main function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
int generatePassword(char* characters[], int i, char s[], int numCharacters, int passwordLength) {
if (i==0) {
printf("%s\n", s);
return 0;
}
for (int j = 0; j < passwordLength; j++) {
strcat(s, characters[j]);
generatePassword(characters, i-1, s, numCharacters, passwordLength);
}
return 0;
}
void homeFunction(char* characters[], int numCharacters, int passwordLength) {
for (int i = 1; i <= numCharacters; i++) {
char s[MAX] = "";
int c = generatePassword(characters, i, s, numCharacters, passwordLength);
}
}
int main (int argc, char *argv[]) {
if (argc < 2) {
printf("ERROR: Program did not execute due to lack of arguments.\n");
return -1;
}
int numCharacters;
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
for (int i = 0; i < numCharacters; i++) {
if (strlen(argv[i+1]) > 1) {
printf("ERROR: You can only input one character at a time.\n");
return -1;
}
}
if (argv != numCharacters + 3) {
printf("ERROR: Invalid number of arguments.\n");
return -1;
}
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(numCharacters * sizeof(char));
for (int i = 0; i < numCharacters; i++) {
charArray[i] = argv[i+2];
}
homeFunction(charArray, numCharacters, passwordLength);
return 0;
}
In theory, if the user ran the program with "./NAME 2 a b 2" the result should be
a
b
aa
ab
ba
bb
This is my current output. How can I make it look like the output above?
a
ab
abaa
abaab
abaabba
abaabbab
You need to learn the fundamentals of arrays and strings.
Imagine if I run your code as app.exe 99
This is undefined behavior:
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
If argv[1] is say, "99", then numCharacters will be 99.
Then passwordLength will be assigned the atoi conversion of argv[101]. But there's only two valid elements in argv: argv[0], which is the executable path, and argv[1], which is "99". argv[2] and up is random memory that's not yours to look at.
This is also wrong:
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(MAX * sizeof(char));
You are allocating an array of (string) pointers, then assigning to an index one past the valid range of the array.

How would I only print out characters that have not appeared before in an argument?

I'm trying to figure out a way to only print out the characters without getting duplicates in C. Any help is appreciated.
For example, if i pass in 'Hello', i would like 'Helo' returned.
My current code that just prints out the passed in argument:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
i = 0;
while (argv[1][i] != '\0')
{
putchar(argv[1][i]);
i++;
}
return (0);
}
Edit: preferably without the use of any extra functions / #includes’s
You can try this. You need an array with the length of the max possible ascii code, to handle the seen characters. Hope this helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int * seen = calloc(256, sizeof(char));
if (argv[1] == NULL) {
printf("No argument.\n");
return 0;
}
for (int i = 0 ; i < strlen(argv[1]) ; i++) {
if (seen[argv[1][i]] != 1) {
seen[argv[1][i]] = 1;
putchar(argv[1][i]);
}
}
free(seen);
}
You can do like this:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
char f[128];
unsigned char ch;
if (argc != 2) {
printf("use : ./a.out str");
return -1;
}
for (i = 0; i != sizeof(f); ++i)
f[i] = 0;
for (i = 0; argv[1][i] != '\0'; ++i) {
ch = argv[1][i];
if (f[ch] == 0) {
putchar(ch);
f[ch] = 1;
}
}
return 0;
}

Segmentation fault in C while using isdigit() and argc

I am having the following issue: Segmentation fault (core dumped).
I looked around at the other questions on StackOverflow and didn't see the correct answer to my question. Here is my code :
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("missing command-line argument\n");
return 1;
}
for (int i = 0; i < argc; i++)
{
printf("Made it inside");
if (isdigit(argv[i]) == 0)
{
return 1;
}
}
string plain_text = get_string("plaintext: ");
int key = atoi(argv[1]); //function to convert a string to int.
for (int i = 0, n = strlen(plain_text); i < n; i++)
{
int c = (int) plain_text[i];
c += key;
printf("%c", c);
}
printf("\n");
return 0;
}
The error is coming from "if (isdigit(argv[i]) == 0)".
EDIT:
Here is the solution, thanks all!
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isdigit(argv[1][i]) == 0)
{
return 1;
}
}
You are passing a string which is actually a char * to isdigit. You need to pass the first character of the string instead
isdigit(*argv[i][0])
isdigit expects an int, you're giving it a string (actually a null terminated group of chars)
http://pubs.opengroup.org/onlinepubs/009696699/functions/isdigit.html
While the behavior is listed as "undefined" in this case, I'm not actually sure why you would get a segfault from it.

C - Better method for replacing

I'm looking to replace words from a file where words.txt contains "banana test apple" would output -> "banana Replaced! apple" The words it would be looking to replace would come as an argument to stdin ("test" in this case)
Not sure where my code is going wrong, and I'm also wondering if there's a better way to do it than get getchar() function, as I find it confusing to work with, and annoying as you cannot backup characters.
Any suggestions? Thanks
$ ./a.exe test < words.txt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
int c = getchar();
int counter = 0;
int i,index;
for (i = 1; i < argc; i++){
for (index = 0; index < strlen(argv[i]); index++){
while (c == argv[i][index]){
counter++;
c = getchar();
index++;
if (counter == strlen(argv[i])){
printf("Replaced!");
}
}
printf("%c ",c);
c = getchar();
counter = 0;
}
}
return (0);
}
I would do it as follows :
read all the file into a buffer using fgets
looking for the key work (test) using strstr
replace it with your new string using strncpy
write to file (or output to stdout) whatever you want to do
You could use scanf to read in a word at a time:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char wordbuffer[100];
while (scanf("%99s", wordbuffer) == 1)
{
int replace = 0;
for (int i = 1; i < argc && !replace; i++)
if (strcmp(wordbuffer, argv[i]) == 0)
replace = 1;
if (replace)
printf("Replaced! ");
else
printf("%s ", wordbuffer);
}
}
If you are using a modern system that compliant with the latest POSIX specification, you can take advantage of the m assignment-allocation character, and have the appropriate amount of space allocated for you, so that you don't have to use some arbitrary maximum number of characters.
int main(int argc, char *argv[])
{
char *wordbuffer;
while (scanf("%ms", &wordbuffer) == 1)
{
int replace = 0;
for (int i = 1; i < argc && !replace; i++)
if (strcmp(wordbuffer, argv[i]) == 0)
replace = 1;
if (replace)
printf("Replaced! ");
else
printf("%s ", wordbuffer);
free(wordbuffer);
}
}

Resources