I am trying to construct a simple programme to acquaint myself with command line functionality, I seem to have formatted something incorrectly, but I find it very difficult to understand precisely what the resulting error message means. My intenion is to create a programme which checks that all the characters in the command line are digits. Here is my code:
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
for (int i = 0; i < strlen(argv); i++)
{
if (!isalnum(argv[i]))
{
printf("Please provide letters or numbers only");
}
else
{
printf("Success!");
}
}
}
The error message I receive when I attempt to compile is: c:9:32: error: incompatible pointer types passing 'char **' to parameter of type 'const char *'; dereference with * [-Werror,-Wincompatible-pointer-types].
argv is an array (pointer) of pointers to strings.
isalnum is checking a character, not a whole string, so you will need two loops: to check each strings and to check each characters in the strings.
This code won't get the warning:
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
for (int c = 1; c < argc; c++) // loop for checking each strings
{
for (int i = 0; i < strlen(argv[c]); i++) // loop for checking each characters in the strings
{
if (!isalnum(argv[c][i]))
{
printf("Please provide letters or numbers only");
}
else
{
printf("Success!");
}
}
}
}
But you may want this code with implovements:
Print the message only once instead of for each characters.
Use size_t for looping until the length of the string.
Call strlen() once before the loop instead of calling in each iteration.
Use puts instead of printf to print newline character at the end of output.
Add return 0; to clarify that the code returns 0.
Remove unnecessary #includes, including non-standard one.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int all_ok = 1;
for (int c = 1; c < argc; c++)
{
size_t len = strlen(argv[c]);
for (size_t i = 0; i < len; i++)
{
all_ok = all_ok && isalnum(argv[c][i]);
}
}
if (!all_ok)
{
puts("Please provide letters or numbers only");
}
else
{
puts("Success!");
}
return 0;
}
Related
I'm on the stage where we need to correctly setup the command line argument to take only digits and to break out of the code if the user types anything else other than a digit. (leaving it empty, inputting two digits, inputting text, inputting two pieces of text etc.)
So I made the program work correctly if the user types more than one command line argument or one command line argument which isn't a digit. My problem is that if I leave the command line argument blank the program gives me a segmentation fault and it doesn't work as intended if I type a single command line like "1d". Can anyone tell me where I went wrong? I'm stuck. Here's the code:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
bool only_digits(string argv[]);
int main(int argc, string argv[])
{
bool digits = only_digits(argv);
if(argc != 2 || digits == false)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
return 0;
}
}
bool only_digits(string argv[])
{
bool digit = false;
for(int i = 0; i < strlen(argv[1]); i++)
{
if(isdigit(argv[1][i]))
{
digit = true;
}
}
return digit;
}
You have two problems:
You're calling only_digits() before checking whether argv[1] exists. So you get a segfault if there are no command-line arguments. Fix this by calling only_digits() after the argc check.
The condition in only_digits() is backwards. It returns true if any character is a digit, but it's supposed to return true only if all the characters are digits.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
bool only_digits(string argv[]);
int main(int argc, string argv[])
{
if(!(argc == 2 && only_digits(argv)))
{
printf("Usage: ./caesar key\n");
return 1;
}
return 0;
}
bool only_digits(string argv[])
{
for(int i = 0; i < strlen(argv[1]); i++)
{
if(!isdigit(argv[1][i]))
{
return false;
}
}
return true;
}
I have been trying to write a C program where the user inputs a command-line argument and the program checks if it is all number digits or not. If that is true, the program simply reprints what the user put in. If that is false and there is at least one non-number mixed in, the program just prints the word "bad" once.
What I have come up so far consists of the program checking each character of the input individually. However, what ends up happening once I put in a mixture of numbers and letters in is that the program would still print the numbers, and then once it gets to printing a letter, it prints the word "bad".
Here's an example:
I put ./program 100x into the terminal
=> Expected result: bad
=> Actual result: 100bad
Here's the code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
for(int i = 0; i < strlen(argv[1]); i++) {
if (isdigit(argv[1][i]) != 0) {
printf("%c", argv[1][i]);
return 0;
} else {
printf("bad");
return 1;
}
}
}
First, I don't think your program is doing what your describe because it returns at the first digit encountered. Then, as soon as you see a digit you print it, you want to first check that your input is right and then print it. Taking your implementation, you could modify it like that:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
// checking input
for(int i = 0; i < strlen(argv[1]); i++) {
if (!(isdigit(argv[1][i]) != 0)) {
printf("bad\n");
return 1;
}
}
// here you know your input is good
// prints input
printf("%s\n", argv[1]);
return 0;
}
Try this one :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
//for(int i = 0; i < strlen(argv[1]); i++)
{
//if (isdigit(argv[1][i]) != 0)
if(strspn(argv[1], "0123456789" )== strlen(argv[1]))
{
printf("%s", argv[1]);
return 0;
}
else
{
printf("bad");
return 1;
}
}
}
Your logical error is that your program checks one character and immediately prints a digit or a bad message, and so continues with each character. However, you need to try writing an algorithm that first checks the whole string for characters other than numbers. If the algorithm finds at least one character (the result is false), it can close loop by using "break" keyword and print "bad" after. OR if all characters are numbers, you can return the value true and only then print them on the screen.
I am trying to create a cipher coder in C, so far I have the following code. The if statement doesn't work properly and pops up segmentation fault whenever something is inputted whether it be a digit or just a letter. The else statement which is supposed to print out how to use the cipher text only prints it out when there is a space.
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int main(int argc, string argv[]) //im certain the problem is on this line but I dont know where exactly nor do I know how to fix it
{
if (isdigit(argv[1]))
{
string s = get_string("Cipher Text: ");
}
else
{
printf("Usage: ./caesar key\n");
}
}
I'm certain the error has to deal with the string in the command line argument but I'm not to sure on what steps to take to fix it.
This is a very small program to show how you can access arguments of a C program.
It only uses standard C features (not CS50 or special string type).
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
printf("argc=%d\n", argc);
for (i=0; i < argc; i++)
printf("argv[%d]=%s\n", i, argv[i]);
return 0;
}
I'm finding that my very basic code to lowercase a string is sometimes outputting an extra character. If I run vigenere with some inputs, it works correctly:
~/workspace/pset2/vigenere/ $ ./vigenere tweedDLed
tweeddled
But for other inputs, it inserts an extra character at the end:
~/workspace/pset2/vigenere/ $ ./vigenere tweedDLedf
tweeddledfB
or...
~/workspace/pset2/vigenere/ $ ./vigenere bkls33bf
bkls33bfW
What is going on here? I am not finding anything with the debugger as the character array is not displayed. This is my code:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cs50.h>
int main(int argc, string argv[]){
if (argc!=2){
return 1;
}
else{
int n = strlen(argv[1]);
char cipherKey[n];
for (int i=0;i<n;i++){
cipherKey[i]=tolower(argv[1][i]);
}
printf("%s\n",cipherKey);
}
}
You need to allocate space for the string termination character, and you need to terminate your string. Otherwise, you leave your string unterminated, printf may read out of the string's bounds yielding undefined behaviour (e.g. in form of "weired" output). You could correct this as follows:
int n = strlen(argv[1]);
char cipherKey[n+1];
for (int i=0;i<n;i++){
cipherKey[i]=tolower((unsigned char)argv[1][i]);
}
cipherKey[n]='\0';
I'm making a little program in C where I would put in a couple of numbers and dots and then delete all the dots (.).
I was thinking about a whileloop but I cannot seem to quite understand what I should do next. So far I got this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0)
{
//?????
}
return 0;
Am I on the right track or should I start differently and not use a while loop at all? I can only find solutions where there is a specific string that is not written by the user, but by the programmer...
Put in an IF to only print characters that aren't a dot. Like the others suggested, you should probably change the gets to fgets as well.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0) {
if ( s[k] != '.' ) {
printf("%c", s[k]);
}
k++;
}
printf("\n");
return 0;
}
With a while loop, I'm also worried that if the user puts in a full 30 characters, you won't reach your exit condition. To avoid this problem, a for loop would be better (since you already know the size of the array). However, if you do it this way, you'll also need to initialize your array "s" to be blank.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
for ( k = 0 ; k < 30 ; k++ ) {
if ( s[k] != '.' && s[k] != 0 ) {
printf("%c", s[k]);
}
k++;
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0)
{
if(s[k] == '.')
s[k] = s[k + 1];
k++;
}
s[k] = '\0';
return 0;
#include <stdio.h>
//remove the specified character from str
char *strrmc(char *str, char ch){
char *from, *to;
from = to = str;
while(*from){
if(*from == ch)
++from;
else
*to++ = *from++;
}
*to = '\0';
return str;
}
int main(int argc, char *argv[]){
char s[30] = "192.169.007";
printf("%s\n", strrmc(s, '.'));//192169007
return 0;
}
Here's one way you might go at it - it's different from how you've started, but can easily be modified. It could be improved on as well, but we can quibble about that in further comments. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
/* Take account number in as argument to executable */
int dotless_length = 30;
char dotless[dotless_length];
int k = 0;
int i = 0;
while (argv[1][k] != '\0' && i < dotless_length) {
if (argv[1][k] >= 48 && argv[1][k] <= 57) { /* ascii decimal codes for 0-9 */
dotless[i] = argv[1][k];
i++;
}
else if (argv[1][k] != '.') {
printf("invalid input: %c\n", argv[1][k]);
return 1;
}
k++;
}
dotless[i] = '\0'; /* null-terminate it! */
printf("Account number without dots: %s\n", dotless);
return 0;
}
Then compile with gcc -Wall -o zdotless filename.c and run with
./zdotless 401.863.3000 as an example.
Notes: This may look more harder since it goes into input sanitation (and cleanliness) a little more than your original - e.g.
not assuming that user input consists solely of numbers and periods,
saving the resulting dotless string (for presumable future manipulations?),
having one place to change the length of dotless (a step towards not hardcoding it), and
not being interactive.
When you call an executable, argv is what you've typed, so argv[0] is the executable name (./zdotless), argv[1] is the next argument (401.863.3000 as a string), and so on if there are more arguments. Since argv[1] is the string representation of your dotty input number, argv[1][0] is the first character of it, etc.
Since we're copying to dotless character-by-character rather than using string manipulation, you've got to tack on a null character manually. (That same null character is what you'd loop until reaching, when initially reading the input string.) Other questions?...