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");
}
Related
#include <cs50.h>
#include <stdio.h>
#include<ctype.h>
int main(int argc, string argv[])
{
int KEY;
if(isdigit(argv[1]))
{
KEY = (int)argv[1];
}
else
{
printf("Usage: ./caesar key");
}
printf("\n");
printf("%i\n",argc);
}
I can't find out the problem when I type the following
How do I fix it?
This is not a high-level language with various syntax sugar features.
Important Notes:
Conversion of const char * to int is not done by just type-casting it.
isdigit() works only for int (single characters), not const char * it will cause Undefined Behavior.
argc is the length of pointer array argv
string is not a valid type for main() function arguments, it should be int main(int argc, char const **argv) { }
Must check whether argv[1] even exists or not
Once you print the usage your program should exit
Any error message should be printed on stderr
Must Use return EXIT_SUCCESS;, which is defined in the header file stdlib.h, when exiting the application, or use return EXIT_FAILURE; if something goes wrong.
Final Code
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char const **argv)
{
if(argc == 1)
{
fprintf(stderr, "Usage: %s <KEY>", argv[0]);
return EXIT_FAILURE;
}
for(size_t i = 0; argv[1][i]; i++)
{
if(!isdigit(argv[1][i]))
{
fprintf(stderr, "expected only integer value\n");
return EXIT_FAILURE;
}
}
// we don't need to check whether `argv[1]` is all digit or not at this point
int KEY = strtod(argv[1], NULL);
printf("argc = %d\n", argc);
printf("KEY = %d\n", KEY);
return EXIT_SUCCESS;
}
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;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check for correct 1 integer argument else print instructions
if (argc == 2 && isdigit(*argv[1]))
{
printf("plaintext: ");
printf("rawtext: ");
return 0;
}
else
{
printf("Usage: [KEY]\n");
return 1;
}
}
The program should print "Usage: [KEY]" if the user enters ./program 2z but isdigit is not catching "z". Is there a way to correct this or is there any other alternative to isdigit function?
You need to call isdigit() in a loop, testing each character, since it only checks one character at a time.
if (argc == 2 && argv[1][0]) {
for (int i = 0; argv[1][i]; i++) {
if (!isdigit(argv[1][i]) {
printf("Error: key must be numeric\n");
return 1;
}
}
printf("plaintext: ");
printf("rawtext: ");
return 0;
} else {
printf("Usage: %s key\n", argv[0]);
return 1;
}
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...
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 + !.