CS50 Problem Set 2--Segmentation fault (core dumped) - c

So I've been working on this code for about a day now and finally managed to create the file without an error message popping up. As soon as I run it, though, this pops up:
Segmentation fault (core dumped)
`
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int k=atoi(argv[1]);
if (argc!=2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else if (argv[1]<0)
{
printf("Usage: ./caesar key\n");
return 2;
}
else if (argv[1]== NULL)
{
printf("Usage: ./caesar key\n");
return 3;
}
string plaintext= get_string("plaintext: ");
printf("ciphertext: ");
for(int i=0; i<strlen(plaintext); i++)
{
if(plaintext[i]>='a' && plaintext[i]<='z')
{
printf("%c", ((plaintext[i]-97+k)%26)+97);
}
else if(plaintext[i]>='A' && plaintext[i]<='Z')
{
printf("%c", ((plaintext[i]-65+k)%26)+65);
}
}
printf("\n");
}
`
Can anyone tell me what I'm doing wrong here?
Haven't really tried anything to resolve this yet.

Even without seeing where it core dumps, I can see a number of issues with the code.
First thing is that you try to dereference argv[1] before checking how many parameters there are. i.e.
int k=atoi(argv[1]);
comes before
if (argc!=2)
{
printf("Usage: ./caesar key\n");
return 1;
}
If you run your program without putting in a value for the offset, this will cause a segmentation fault because C runtimes put a null pointer after the pointer to the last argument. So if you just typed ./caesar on the command line, argc is 1 and argv[1] is NULL.
This is the most likely cause of your crash.
This line:
else if (argv[1]<0)
doesn't really make any sense. You're comparing a pointer to 0. In many (all?) implementations, pointers behave like unsigned integers under comparison, so no pointer is ever less than zero.
This line
else if (argv[1]== NULL)
Is redundant if you have already checked that argc is two. Because, if argc is two argv[0] and argv[1] are guaranteed to point to strings.
On an unrelated note, I'd say that you should never do what that cs50.h header file does, which is have a typedef of something to char *. It just obfuscates what a string is.

Related

Segmentation fault (core dumped) CS50 error

I have been writing a program for CS50 (caesar) that is supposed to use a key given by the user in the command line to encrypt a message. The program is supposed to test the key given for a number of conditions. I want my program to use return values to stop running when the command line argument given is invalid.
Code below: (I have not finished it, so far it only checks for the command line input)
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int char_repeat(string key);
int key_check(string key);
int main(int argc, string argv[])
{
string key = argv[1];
for (int i = 0; i < strlen(key); i++)
{
char c = toupper(key[i]);
// conditions for key (string) written in argv[1]
if (argc < 2 || strlen(key) != 26 || c < 65 || c > 90)
{
printf("Usage: ./substitution key\n");
return 1;
}
}
char_repeat(key);
printf("this should not print if invalid...");
return 0;
}
int char_repeat(string key)
{
// check for repeated characters in key
for (int i = 0; i < strlen(key); i++)
{
for (int j = i + 1; j < strlen(key); j++)
{
if (toupper(key[i]) == toupper(key[j]))
{
printf("Usage: ./substitution key\n");
return 1;
}
}
}
printf("this should not print if invalid...");
return 0;
}
When I give 'invalid' inputs such as
$ ./sub AB*DEFGHIJKLMNOPQRSTUVWXYZ
$ ./sub ABC
$ ./sub ABCABCABCABCABCABCABCABCAB
$ ./sub ABCDEFGHIJKLMNOPQRSTUVWXYZ-
The code works perfectly by printing "Usage: ./substitution key\n" skipping my test print message, "this should not print if invalid...".
YET, and this is the problem, if I run ./sub without giving it a second argument. That is,
$ ./sub
I get an error message
segmentation fault (core dumped)
In the code itself I use the condition (argc < 2) in one of the if statements so shouldn't it work as all the other conditions and print "Usage: ./substitution key\n" ? I know segmentation fault is an error with trying to access memory that shouldn't be accessed or some other type of memory corruption, I just don't see how this relates to my program. I would imagine it is a problem the way I am using return.
Thank you in advance!
A segmentation fault is an error caused by attempting to access memory that does not belong to you.
When you run your program without providing additional arguments by using the command ./sub the code in the program tries to access argument 2 which does not exist, so you do not have access to that memory.
string key = argv[1];
Instead, you should check before you try to access that memory that arguments have been passed in.
if(argc < 2)
{
printf("Usage: ./substitution key\n");
return 1;
}
string key = argv[1];

Why is this my code producing a segmentation fault when there is only argc[1]?

I'm taking a intro CS course (CS50x) and came across a slight problem.
Why is this C code producing a segmentation fault when there is only argc[1]?
It should print the statement. Why won't it print the error?
Thanks in advance!
int main(int argc, string argv[])
{
//HOUSEKEEPING
//Get/Validate Key
string key = argv[1];
int finalKey = atoi(key) % 26;
while (argc != 2)
{
for (int i = 0; i < strlen(key); i++)
if (!isdigit(key[i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
//...
argc is an integer argument that keeps track of the number of arguments in the command line, there is no argc[1], there might be an argv[1] if you provide a second command line argument, otherwise trying to read from a non existing argv[x] amounts to undefined behavior, and is the likely culprit of the segmentation fault you are experiencing.
In light of that information you'll notice that the while statement makes little sense, argc remains unchanged so the loop will either never execute, or will be infinite if argc is not 2 (and the program doesn't crash).
The if-else is also fishy, it will always print the message and return, if the character is a digit or is not a digit alike.
Notwithstanding the goal of the program, a syntactically correct code should look more like this:
int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv[1];
int finalKey = atoi(key) % 26; //*
for (int i = 0; i < strlen(key); i++)
{
if (!isdigit(key[i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
else
{
puts("Wrong number of arguments, usage: ./caesar key\n");
}
}
* Note that atoi is quite unsafe, consider using strtol. And you can operate directly in argv[1] i.e. int finalKey = atoi(argv[1]) % 26;
I think you are not clear about the operation of argc and argv. argc indicates the number of parameters passed to the main function. At least it will receive one argument (argv[0], which will be the name of the compiled C code). In addition, it will receive all the parameters that you pass through the command line.
In summary, the correct way to do it would be:
if (argc >=2){
string key = argv[1];
}
Otherwise, you will have a segmentation fault when you try to access the argv[1] value.

Segmentation Fault Due to Lack of Command Line Argument (argv[1])

This segment of code is meant to check if a user has entered only one numeric command-line argument, and return an error code of "1" if this is not the case. I have the code set up so that it first checks if argc is anything other than 2. Unfortunately, I am still receiving Segmentation Faults if no command line argument is entered, and I'm not sure why this code doesn't catch a null amount of command line arguments.
I tried moving the "if (argc !=2)" formula above the entire "for" statement to try and catch the command line argument issue right from the beginning, but I received the same result.
My question is, why am I receiving a Segmentation Fault when no command line argument is provided, and what am I missing to ensure the program doesn't Seg Fault with no command line argument?
Due to course policy, I will only be providing the segment of code in question.
#include <unistd.h>
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// add'l variables //
int k = atoi(argv[1]);
for (int i = 0; i < strlen(argv[1]); i++)
{
if (argc != 2)
{
printf("Please enter only 1 command-line argument.\n");
return 1;
}
else if (!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// add'l code //
Error as shown in Terminal
You must first check the argc before using the argv[1], because argv[1] may not have a valid pointer if argc < 2. A corrected version of your code could be like that:
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int i = 0;
if (argc != 2) {
printf("Please enter only 1 command-line argument.\n");
return 1;
}
while (isdigit(argv[1][i]))
++i;
if (argv[1][i] != '\0') {
printf("Usage: ./caesar key\n");
return 1;
}
return 0;
}

Segmentation fault error ( cs50 problemset week2)

I try to get the user to type a specific command line to execute my program, but ./caesar leads to segmentation fault, while no return statement is included. With return statement, everything works perfectly.
Can someone explain to me why that's the case and if there is another solution to fix this?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("Usage: ./caesar key\n");
//return 1;
}
for(int i = 0, p = strlen(argv[1]); i < p; i++)
{
if(isalpha(argv[1][i]))
{
printf("Usage: ./caesar key\n");
}
}
}
return exits your function early, so the code afterwards doesn't get run. If you don't provide an argument, argc won't be 2, and argv[1] wouldn't be a valid string. With a return, then usage message prints and then the return stops execution there, so you don't try to call strlen(argv[1]), which will segfault.
Without the return, you print the usage message, but the code keeps running, and you call strlen(argv[1]), which will cause a segfault.

What do I need to change so cs50 Caesar only prints the correct message after i iterate over each character?

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.

Resources