I don't understand why it isn't working. It complains when there are 3 or more args but not when there is only the one Vigenere arg. I have looked at other people who had same problem and they said this worked to resolve.....not sure what I am missing here. When I run ./vigenere, I get a segmentation fault. It works normally with 2 arg like ./vigenere bard and complains when extra arguments are given like ./vigenere bard dfads.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc,string argv[])
{
string sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
string sPlainText = "";
int counter = 0;
int iAccept = 0;
do
{
if(argc != 2) // <-----this should work whats wrong?
{
printf("Invalid argument! Please enter program name and keyword.\n");
return 1;
}
else if(argv[1])
{
for(int i = 0; i < iKeyLength; i++)
{
if (!isalpha(argv[1][i]))
{
printf("Invalid entry, please use letters only.\n");
return 1;
}
else
{
iAccept = 1;
}
}
}
}while(iAccept == 0);
for(int i = 0; i < iKeyLength; i++)
{
iKey[i] = toupper(sKeyWord[i]) - 65;
}
sPlainText = GetString();
int iPlainText = strlen(sPlainText);
for(int j = 0; j < iPlainText; j++)
{
if(!isalpha(sPlainText[j]))
{
printf("%c",sPlainText[j]);
counter++;
}
if(islower(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 97) + iKey[(j - counter)%iKeyLength])%26)+ 97));
}
if(isupper(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 65) + iKey[(j - counter)%iKeyLength])%26)+ 65));
}
}
printf("\n");
return 0;
}
I'd rewrite the top, argument handling section of your program like this.
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s key\n", argv[0]);
return 1;
}
char *sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
for (int i = 0; i < iKeyLength; i++)
{
if (!isalpha(sKeyword[i]))
{
fprintf(stderr, "%s: Invalid character '%c' in key; please use letters only.\n",
argv[0], sKeyword[i]);
return 1;
}
iKey[i] = toupper(sKeyWord[i]) - 'A';
}
…your code to read the text to be enciphered and encipher it, etc…
The key point is to check that there is an argv[1] before trying to do anything with it. I eliminated a do { … } while (…); loop because the argument isn't going to change on a second iteration. That allows the iAccept variable to be eliminated. Note that errors are reported on standard error, not standard output. Also notice that the messages are preceded by the program name (argv[0]). A 'Usage' message is often the best way to report a problem; it's a simple reminder to those who run the program what's required. Note too that the error message for the alphabetic check reports the erroneous character; that helps people see what the program thinks is wrong.
This is more or less what the comments were suggesting should be done.
I've not reviewed the enciphering code; there could be undiagnosed problems in that too. There are many related questions on SO that would provide you with answers to any such problems, though.
Related
Here is the code:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, string argv[])
{
string key = argv[1];
string keyupper = argv[1];
string keylower = argv[1];
if (argc != 2) //makes sure there is exactly 2 arguments (the program executable and the key)
{
printf("Please input a key.\n");
return 1;
}
else if (strlen(key) != 26) //makes sure the key is exactly 26 letters
{
printf("Please make sure the key is 26 unique letters.\n");
return 1;
}
for (int i = 0; i < 26; i++) //the loop to make the uppercase key
{
keyupper[i] = toupper(keyupper[i]);
}
for (int i = 0; i < 26; i++) //the loop to make the lowercase key
{
keylower[i] = tolower(keylower[i]);
}
Essentially, I want to make a very basic encryption using a key entered while executing the program, it needs to contain 26 unique letters. I want to create two arrays, an uppercase and a lowercase one, to make everything else much easier for me, but when running this code, all keys become either uppercase or lowercase depending on which loop is created last (in this case, they all become lowercase). Even key gets changed to lowercase even though it's used only once as a declaration. Everything else works but this.
This is for the CS50 course so functions such as toupper() are included in libraries.
This is my first ever question so sorry if it's worded poorly. Thank you!
Code failed to copy the string contents
[Talking about string here, not the type string]
In C, a string is "... is a contiguous sequence of characters terminated by and including the first null character."
Code only copied pointers and not the string contents.
string key = argv[1];
string keyupper = argv[1];
string keylower = argv[1];
Comment discussion indicates OP now sees why code is in error.
Repaired code
//#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// Avoid naked magic numbers, instead define them
#define KEY_N 26
int main(int argc, string argv[]) {
// Do not code argv[1] until after argc check
// string key = argv[1];
// string keyupper = argv[1];
// string keylower = argv[1];
if (argc != 2) {
printf("Please input a key.\n");
return 1;
}
char *key = argv[1];
// else if (strlen(key) != 26)letters
if (strlen(key) != KEY_N) {
printf("Please make sure the key is 26 unique letters.\n");
return 1;
}
char keyupper[KEY_N + 1];
char keylower[KEY_N + 1];
// for (int i = 0; i < 26; i++)
for (size_t i = 0; i < KEY_N; i++) {
// keyupper[i] = toupper(keyupper[i]);
keyupper[i] = toupper((unsigned char) key[i]);
}
keyupper[KEY_N] = '\0';
...
I am stuck trying to iterate over each character to detect whether or not it is a digit, while only printing the answer once. The problem I'm having is I can get it to detect whether a character is a digit or not, but it prints out an answer for each number I put in until it reaches a letter. I'm looking how to get it to detect whether or not the input is a number or letter, and then make a decision on what to print out instead of printing success every time it detects a number. Feel like its something with my for loop but cant quite figure it out. Thanks.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string n = argv[1];
if (argc != 2)
{
printf("usage: ./caesar key\n");
return 1;
}
else
{
for(int i = 0, length = strlen(n); i < length; i++)
if(!isdigit(n[i]))
{
printf("usage: ./caesar key\n");
return 1;
}
else
{
int convert = atoi(n);
printf("Success\n");
printf("%i\n", convert);
}
}
}
The problem is that inside the for you have an if-else statement... that means that one of both will always execute for every iterarion.
For printing success just once, you should erase the else keyword (and for clarity the brackets) but keeping the else code.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string n = argv[1];
if (argc != 2)
{
printf("usage: ./caesar key\n");
return 1;
}
else
{
for(int i = 0, length = strlen(n); i < length; i++)
{
if(!isdigit(n[i]))
{
printf("usage: ./caesar key\n");
return 1;
}
}
int convert = atoi(n);
printf("Success\n");
printf("%i\n", convert);
}
}
What do I need to change so cs50 Caesar only prints the correct message after i iterate over each character?
It seems you aren't aware that you don't have to do that. The Caesar Specification says:
You can assume that, if a user does provide a command-line argument, it will be a non-negative integer (e.g., 1). No need to check that it’s indeed numeric.
I am trying to build an echo-like command which I named code at xv6. The problem is that if:
Input:
$code Hello World
Output:
user space:Hello user space:World
While the correct output should be:
user space: Hello World
Can somebody help me?
int
main(int argc, char *argv[])
{
int i;
if(argc <= 1){
printf(1," %s user space:", argv[0]);
exit();
}
for(i = 1; i < argc; i++){
printf(1, " print in user space:%s",argv[i]);
}
printf(1, "\n");
exit();
}
program name is also passed as argument to your main function so you have three(as hello and world are considered separate arguments) arguments here .there is several issues in your code ,as you have two arguments first if statement will be false ,and you are not printing correctly in for loop ,following might be helpful :
int main(int argc, char *argv[])
{
int i;
printf("number of arguments : %d ",argc);
//argv array index count from 0
for(i = 0; i < argc; i++){
printf("argument number %d : %s",i,argv[i]); // issue in your code
}
printf("\n");//issue in your code
exit(0);
}
It's possible to use the write command so that you can output to stdout. Between each command line argument an additional space needs to be written.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
write(1, "user space: ", 12);
for (i = 1; i < argc; i++) {
size_t len = strlen(argv[i]);
write(1, argv[i], len);
write(1, " ", 1);
}
write(1, "\n", 1);
return 0;
}
The problematic part in your code is here:
for(i = 1; i < argc; i++){
printf(1, " print in user space:%s",argv[i]); //" print in user space:" is printed
//for each iteration
}
As others pointed out, you should rather do:
printf(" print in user space:\n");
for(i = 1; i < argc; i++){
printf("%s",argv[i]);
}
That said, a few more remarks for you:
I never seen a printf that takes an integer as first argument, I assume that the first parameter is not important/is a typo
I am not an expert unix developer, but you can just use "return 0" (or "return 1") to quit your program. You will also be able to return an error code this way, as most unix programs do
If you decide to use printf, be aware that it comes with a nasty security exploit which can expose the caller's stack to a malicious user. Make sure your input is well formed or use a different function if possible
The below code (which compiles fine) checks for non-alphabetical characters in a command-line input, however I feel like there's got to be a better way to write this. For example, you can see that there is no code that executes in the core if statement that checks each character in the string. Is there a way to check if one of the characters is not an alphabetical character and throw the error, rather than have the error in the else function?
int main(int argc, string argv[]){
// terminate program if more than one key
if(argc != 2){
printf("error");
return 1;
// check to ensure key characters are alphabetical
} else {
for(int h = 0; h < strlen(argv[1]); h++){
if(isalpha(argv[1][h])){
} else {
printf("error");
return 1;
}
}
}
}
Strings are usually short, but calling strlen() ina for loop condition is a bad habit. It's O(N squared) because the entire string is scanned on each iteration.
Write the function like this
int allalpha(const char *str)
{
size_t i;
for(i=0;str[i];i++)
if(!isalpha(str[i]))
return 0;
return 1;
}
Then in main
if(!allalpha(argv[1]))
{
/* non all-alpha error handling code here */
}
Yes, you can invert the if-condition, which is the general solution in these cases.
int main(int argc, string argv[]){
// terminate program if more than one key
if(argc != 2){
printf("error");
return 1;
} else {
// check to ensure key characters are alphabetical
for(int h = 0; h < strlen(argv[1]); h++){
if(!isalpha(argv[1][h])){
printf("error");
return 1;
}
}
}
}
My goal is to have the user view the history of entered commands (historyArray - done) and allow him to re-run any command in history, by entering history 1, history 2 where 1 and 2 is the number of the list of commands as printed-out from historyArray.
I have managed to obtain the index from the second parameter (history 1) of the user input. My question is now, how to execute that specific command obtained from history N?
So, for example:
hshell> test [Enter]
Command not found
hshell> history 1
Command not found
Here is my progress:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[])
{
int i=0; int j=0; int k=0;
int elementCounter = 0;
char inputString[100];
char *result=NULL;
char delims[] = " ";
char historyArray[30][20] = {0};
char tokenArray[20][20] ;
int tempIndex = 0;
char hCommand[2][20]={0};
do
{
j = 0;
printf("hshell>");
gets(inputString);
strcpy (historyArray[k], inputString);
k = (k+1) % 20;
if (elementCounter <= 20)
{
elementCounter++;
}
if (elementCounter == 21)
{
k = 20;
for (i=0; i<20; i++)
{
strcpy(historyArray[i], historyArray[i+1]);
}
strcpy (historyArray[19], inputString);
}
// Break the string into parts
result = strtok(inputString, delims);
while (result!=NULL)
{
strcpy(tokenArray[j], result);
j++;
result= strtok(NULL, delims);
}
if (strcmp(tokenArray[0], "exit") == 0)
{
return 0;
}
else if (strcmp(tokenArray[0], "history") == 0)
{
if (j>1)
{
tempIndex = atoi(tokenArray[1]);
strcpy(hCommand,historyArray[tempIndex-1]);
puts(hCommand);
// tempIndex = atoi(tokenArray[j]);
//puts(tempIndex);
}
else
{
//print history array
for (i=0; i<elementCounter-1;i++)
printf("%i. %s\n", i+1, historyArray[i]);
}
}
else
{
printf("Command not found\n");
}
}while (1);
}
hCommand is where I store the command as obtained from historyArray.
I am using a Windows machine.
After getting the name of the command you wanna execute I would suggest going through the system call exec. Take into account the exec replaces the current process image with the one you are going to execute. Otherwise you might be interested in fork.
EDIT#1 Then I believe you need this API. Note that I am not familiar which of those functions are equivalent to the ones I have provided in first place. With a bit time you could figure it out, right? :)
You can use the 'system' function in stdlib.h.
#include <stdlib.h>
int system(const char *command);
This function is included in both windows and *nix. You do not need to worry about calling fork or CreateProcess separately, this will take care of it for you. See the MSDN documentation for details.
In your code, you would write:
system(hCommand);
It will return when the command finishes (it is a synchronous call).