I'm trying to check argument count, which should return 1 if there is no argument or more than 2 arguments in command line:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
char *key = argv[1]; //taking the key from CL
int n = strlen(key); //length of CL arg string
if (argc != 2) //checks the amount of CL args
{
printf("Usage: ./substitution key\n");
return 1;
}
for (int i = 0; i < n; i++) //validating the key array
{
if (n != 26)
{
printf("Key must contain 26 characters.\n");
return 1;
}
else if (!isalpha(key[i]))
{
printf("Key must contain only alphabetic character.\n");
return 1;
}
for (int j = i + 1; j < n; j++)
{
if (key[i] == key[j])
{
printf("Key must not contain repeated characters.\n");
return 1;
}
}
}
}
When i'm running without an argument it throws an error:
runtime error: null pointer passed as argument 1, which is declared to never be null
Segmentation fault (core dumped).
If i'm commenting key validating part, it runs.
I'm new in C programming and googled it a lot.
Please, help me figure out why?
You first access argv[1], which may not exist, then you check argc to see if it exists. This is the wrong order. First check argc, then access argv[1]:
int main(int argc, char *argv[])
{
if (argc != 2) //checks the amount of CL args
{
printf("Usage: ./substitution key\n");
return 1;
}
char *key = argv[1]; //taking the key from CL
int n = strlen(key); //length of CL arg string
// remaining code...
Related
I can't understand why my code is stopping at the first char of the command-line arguments.
I think the problem is in the loop, I need it to check if the command-line argument is a digit, so the first and second parts aren't important.
Thank you and sorry for the messy, I am new to this.
int main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
// checking if command-line argument is a number
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
printf("%c\n", argv[1][i]);
if (isdigit(argv[1][i]))
{
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
}
You're doing a return in the valid case, so you're only checking the first char of argv[1].
You want to not terminate the loop in the valid case, accumulating the value.
Here's some refactored code:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
int keyval = 0;
for (char *cp = argv[1]; *cp != 0; ++cp) {
if (! isdigit(*cp)) {
printf("Usage: ./caesar key\n");
return 1;
}
// accumulate the number as we go along, digit-by-digit
keyval *= 10;
keyval += (*cp - '0');
}
printf("keyval=%d\n",keyval);
return 0;
}
Here's an alternate way:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
for (char *cp = argv[1]; *cp != 0; ++cp) {
if (! isdigit(*cp)) {
printf("Usage: ./caesar key\n");
return 1;
}
}
// we can use a standard function to get the value
int keyval = atoi(argv[1]);
printf("keyval=%d\n",keyval);
return 0;
}
Here's another way:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
char *cp;
int keyval = strtol(argv[1],&cp,10);
// invalid digit found
if (*cp != 0) {
printf("Usage: ./caesar key\n");
return 1;
}
printf("keyval=%d\n",keyval);
return 0;
}
Note that strtol will accept a negative value (e.g. -37) as valid. So, if negative values are not acceptable, we'd need an additional check [just before the valid printf]:
// negative value found
if (keyval < 0) {
printf("Usage: ./caesar key\n");
return 1;
}
In my program I get the errors that I controlled, but when I try to avoid those preset errors and enter what I want the user to enter, it returns a segmentation fault.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
string key = argv[1];
if (argc < 2 || argc > 2)
{
printf("Usage: ./substitution key\n");
exit(1);
}
if (argc == 2 && strlen(key) < 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
if (strlen(key) > 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
for (int i = 0; i < 26; i++)
{
if (isalpha(key) == 0)
{
printf("MAKE SURE YOUR KEY ONLY HAS LETTERS\n");
}
}
printf("test");
}
#Retired Ninja is spot on. isalpha on key was causing the segmentation. Here is a slightly optimized way of the code.
#include <stdio.h>
#include "cs50.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./substitution key\n");
exit(1);
}
string key = argv[1];
int keylen = strlen(key);
if (keylen != 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
for (int i = 0; i < 26; i++)
{
unsigned char const c = key[i];
if (!isalpha(c))
printf("MAKE SURE YOUR KEY ONLY HAS LETTERS\n");
}
printf("test\n");
}
I'm trying to use command line arguments and have it read into an array however the complier is giving me this error:
error: invalid initializer
I know I need to use int main(int argc, char *argv[]) to use command line arguments and then I have it set like this to read into the array:
int arr[] = atoi(argv[1]);
Not sure what I am missing as this always worked for me in the past. Any ideas?
If what you are passing through the command line a series of number and you want
to have them in an array, then you can do this:
int main(int argc, char **argv)
{
if(argc < 2)
{
fprintf(stderr, "not enough arguments\n");
return 1;
}
int arr[argc-1];
for(size_t i = 0; i < argc - 1; ++i)
arr[i] = atoi(argv[i+1]);
...
return;
}
The reason why the conversion starts at argv[i+1] and not argv[0] is because
argv[0] has always the string that contains the file name of the executed
binary (more precisely the was you've passed the command in the shell), so
argc is always at least 1. That's why the dimension of arr is argc-1,
because for n arguments, argc will be n+1.
Also be aware that atoi does a poor job when it encounters an error, if the
string is not an integer, then atoi will return 0 and you have no idea whether
this is a legit number of an error in the conversion. Using strtol is a
far better alternative:
int main(int argc, char **argv)
{
if(argc < 2)
{
fprintf(stderr, "not enough arguments\n");
return 1;
}
int arr[argc-1];
char *endptr;
for(size_t i = 0; i < argc - 1; ++i)
{
arr[i] = strtol(argv[i+1], &endptr, 0);
if(*endptr != 0)
{
fprintf(stderr, "The argument #%d is not a number\n", i+1);
return 1; // error
}
}
...
return;
}
This would give you a far better result, because it reacts to error from the
user.
So, I am trying to use argc and argv in Caesars cipher in order to execute the program with just [./ key ;string] (e.g. ./ 13 Caesar). I have tried in lots of ways, although I must admit I am really lost here. I was thinking I should just use main(void) and ask the input with fgets, but I still have some curiosity in: How could I make it work with “int main(int argc, char *argv[])?”. Any clues you can give me?
Thank you for your help. Here is the code with the current outputs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int key;
int result;
char str[60];
int k = 0;
printf("argc =%d\n", argc);
printf("argv =%d\n", argv);
printf("key =%d\n", key);
if (argc != 2)
{
printf("You didn't enter a key.\n");
return 1;
}
else
{
int k = key % 26;
printf("k =%d\n", k);
if (k == 0)
{
printf("Invalid key.\n");
return 1;
}
}
}
Output:
$ ./ceasar 13
argc =2
argv =-13216
key =0
k =0
Invalid key.
Edit: Tentative Answer
int main(int argc, char* argv[])
{
int i;
int key = atoi(argv[1]);
int result;
char str[60];
for (i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
if (argc != 2)
{
printf("You didn't enter a key.\n");
return 1;
}
else
{
if (key == 0)
{
printf("Invalid key.\n");
return 1;
}
}
}
Printing argv with the "%d" specifier is undefined behavior, read printf()'s manual and use "%p".
On the other hand, if you want to print the string you should access the appropriate element with array notation. For example
printf("First Argument: %s\n", argv[1]);
this applies to all arguments, noting that argv[0] is the name of the executable as invoked in the command line.
You should also be careful before accessing argv[1] to check that argc > 2, and always check the current argument + !.
I'm trying to write a program that finds the largest and smallest of 10 numbers.
To use my program, you must use the command line argument -l then numbers to determine largest number, the same for the command -s for smallest numbers.
However, when I don't enter a command at all, and just try to run the program, I receive a segmentation fault. Not sure where I went wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[])
{
int i;
int min,max,num;
char *argv1 = argv[1];
char *small = "-s";
char *large = "-l";
min=max=0;
if (0==strcmp(argv1, small))
{
for (i=2; i<argc; i++)
{
num=atoi(argv[i]);
if(i==2)
{
min=num;
}
else
{
if(min>num)min=num;
}
}
printf("The smallest number is %d\n",min);
}
else if (0==strcmp(argv1, large))
{
for (i=2; i<argc; i++)
{
num=atoi(argv[i]);
if(i==2)
{
max=num;
}
else
{
if(max<num)max=num;
}
}
printf("The largest number is %d\n",max);
}
else
{
printf("Invalid option");
}
return 0;
}
Check the number of arguments before accessing to arguments.
int main(int argc, char* argv[])
{
int i;
int min,max,num;
char *argv1 = argv[1];
char *small = "-s";
char *large = "-l";
/* add from here */
if(argc < 2)
{
fprintf(stderr, "Usage: %s command numbers...\n", argc > 0 ? argv[0] : "");
return 1;
}
/* add until here */
min=max=0;
You're setting char *argv1 = argv[1]; without first checking argc to see how many arguments were passed. This will cause a segfault when you later do if (0==strcmp(argv1, small)) because argv1 isn't pointing at a string like you are expecting it to.
To fix it, just check argc before you start comparing argv1 with anything:
if (argc == 1)
{
printf("Error: -s or -l required\n");
exit(1);
}