So I am new to the C language, I am attempting to write a program that outputs text in either upper or lower case, by inputting either -u or -l. The program compiles, however when I run it, it gives me a segmentation fault. Why?
#include <stdio.h>
#include <string.h>
int main(int argc, char*argv[]){
int i;
int j;
int k;
if(strcmp(argv[1],"-u")){
for(i=0;i<argc;i++){
printf("%s ",toupper(argv[i]));
}
}
else if(strcmp(argv[1],"-l")){
for(j=0;j<argc;j++){
printf("%s ",tolower(argv[j]));
}
}
else{
for(k=0;k<argc;k++){
printf("%s ",argv[k]);
}
}
}
toupper & tolower take an int representing a character and returning an int representing that character as upper or lower case (respectively).
You're doing 2 things wrong with that:
You're passing in the address of a char array (not a single character)
You're using the returned value (int) as if it was a char array (passing it as an input to printf with "%s")
So you're getting some garbage out of the function, and then sending printf into unmapped memory address -> that's your seg-fault.
To make life easy, also consider using the getopt command.
Here you will find an example: http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html#Example-of-Getopt
Related
I have this recursive function which creates all possible strings from a dictionary and encrypt them so that they can be compared with some saved hashes.
Earlier, I had some predefined value for the max length of passwords but I tried to change it with argv[1].
But when I execute my program, I get a Segmentation Fault with not explanation.
By the way, all the includes are present as they should but I didn't put them in the post since it is somewhat bugged.
int recur(char * mot , char * tab,int l,int max_l)
{
// Because this was an exercice we had to do in class , i deleted this part
// so some of my classmates dont copy/paste my code
// if you are interested , contact me
int main(int argc, char *argv[])
{
char letters[36] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9'};
char s[10]="";
s[9]='\0';
int l=0;
int max_l;
sscanf (argv[1],"%d",&max_l);
printf("max_l : %i\n",max_l);
printf("Debut ! \n");
recur(s,letters,l,max_l);
}
Thanks for your time!
printf("Argv[1] : %s\n", max_l);
This is undefined behavior. You are giving wrong format specifier. That's why you get seg fault you are trying to print an int using %s format specifer. It looks for the \0 and then it doesn't. So it accesses some memory which it shouldn't resulting in UB. (And that resulted in segmentation error).
It should be
printf("Argv[1] : %d\n", max_l);
Also another major problem is not every control flow of this recursive function returns int. This is a pathway to bigger problem. In case the there is no return value when one is expected the behavior will be undefined.
I am writing a program that takes a command line argument and user input, and calculates the difference between the two characters (cryptography). I would like to pass my argument into a variable within the program, but am unable to do so.
#include <stdio.h>
int main(int argc, char** argv) {
char plain[2];
char cipher[2]; /*locations of plain and cipher text*/
char *ppoint; /*pointers to plain and cipher*/
char *cpoint;
scanf("%s",plain);
*ppoint=plain[0]; /* ppoint points to 1st character in plain*/
cipher=argv[1]; /* cpoint points to first argument character*/
*cpoint=cipher[1];
printf("%s %d \n",ppoint,plain);
printf("%s %d \n",cpoint,cipher);
return 0;
}
For line 14, I am met with a compiler error ,
(cipher=argv[1];) " Incompatible types in assignment "
I have been experimenting with many methods such as type casting but I can not get anything to work.
I would like the two last lines of my program to output the actual character and their respective ASCII values. Please help me past this block!
UPDATE:
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
char plain;
char *cipher; /*locations of plain and cipher text*/
int *ppoint; /*pointers to plain and cipher*/
int *cpoint;
scanf("%s",plain);
*ppoint=(int) plain; /* ppoint points to 1st character in plain*/
cipher=argv[1]; /* cpoint points to first argument character*/
*cpoint=(int) cipher;
printf("%s %d \n",plain);
printf("%s %d \n",cipher);
return 0;
}
I used type casting to fix any compiler errors. However upon running the program and in putting a value for 'plain', I am met with a segmentation fault. I have looked long and hard but cannot see where this memory error is occurring. Please help.
You are attempting to assign a char pointer to a char array, which is not allowed. You'll need to copy the argument some other way. For example, you could use strcpy:
strcpy(cipher,argv[1]);
Alternatively, you could make cipher be a char pointer instead if you never modify it.
const char *cipher;
...
cipher = argv[1];
try using,
ppoint=(int) plain; /* ppoint points to 1st character in plain*/
Without the '*', as you cannot use the de-referencing operator on the pointer variable as the pointer doesn't point to any location yet.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
int i=0;
int x=0;
int n=0;
argv[i]=GetString()
printf("%c", toupper(argv[i][0]));
for (x=0, n=strlen(argv[i]); x<n; x++)
{
printf("%c", toupper(argv[i+1][0]));
}
printf("\n");
}
The code compiles but does not print the initials of a name entered by the user. For instance, John Smith: JS. I receive a segmentation fault instead.
This program is initials.c for CS50.
Although you didn't show the definition of GetString(), I'm pretty sure you're not calling it correctly, because there's no semicolon after it and you almost certainly do not want to overwrite argv[0]. Compiling with debugging symbols (-g in GCC) and running in a debugger will tell you which line of code crashed the program.
Edit: My guess is that you're crashing when you try to dereference argv[i+1], which is argv[1], a NULL pointer. But running in a debugger could confirm or disconfirm this. You seem to be mixing up the syntax to loop through an argument list with the syntax to read a line from standard input.
It is unorthodox to use argv[0] to hold a pointer to the return value from CS50's GetString() function, though not actually illegal.
You have a syntax error; you've omitted a semicolon after GetString().
With that fixed, your crash-causing problem is in the indexing in the loop; you are indexing argv[i+1][0], but argv[1] is a null pointer unless you provided command line arguments and accessing the null pointer is often a crash (so we can tell you didn't provide any command line arguments).
You can demonstrate with:
$ ./initial xyz <<< "john smith"
JXXXXXXXXXX
$
It didn't crash, and it did repeatedly copy the first letter of the argument converted to upper case (because you keep accessing argv[i+1][0]).
The fixes are correspondingly simple:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
int x = 0;
int n = 0;
string str = GetString();
printf("%c", toupper(str[0]));
for (x = 0, n = strlen(str); x < n; x++)
{
printf("%c", toupper(str[x]));
}
printf("\n");
free(str);
return 0;
}
Example run
$ ./initials <<< "john smith"
JJOHN SMITH
$
This isn't the required output, but it does show the program working safely and gives you a decent basis from which to work to get the correct answer.
I am writing a program that stores information of the iwscan Ubuntu command. I am actually reading properly the file that is created with the information; however, when trying to store data(ESSID in a string, Channel in an int and Quality in a double), I have several problems treating the strings to extract the data...
The code is as following:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
char *tratarEssid(char *cadena);
int tratarCanal(char *cadena);
double tratarCalidad(char *cadena);
int tratarCanal(char *cadena){
char resultado[2];
strncpy(resultado,cadena+9,2);
int canal;
canal=atoi(resultado);
return canal;
}
double tratarCalidad(char *cadena){
char resultado[6];
strncpy(resultado,cadena+8,6);
char num[2];
char den[2];
strncpy(num,resultado,2);
if(strlen(resultado)==5)
strncpy(den,resultado+3,2);
else
strncpy(den,resultado+2,2);
double numerador=atof(num);
double denominador=atof(den);
double calidad=numerador/denominador;
return calidad;
}
char *tratarEssid(char *cadena){
char *essid;
essid=(char *)malloc(sizeof(char)*10);
strncpy(essid,cadena+7,10);
return essid;
}
int main(){
int i;
const char *CHECKCANAL = "Channel:";
const char *CHECKQUALITY = "Quality=";
const char *CHECKESSID = "ESSID:";
double calidad;
int canal;
char *essid;
char cadena[20];
system("iwlist wlan0 scan | egrep \"(Channel|Signal level|ESSID)\">/home/wein/Escritorio/basic/bin/Debug/Lista.txt");
printf("Lista hecha\n");
lista=fopen("Lista.txt","r");
printf("Lista abierta\n");
while (!feof(lista)){
fgets(cadena,20,lista);
printf("%s",cadena);
if (strncmp(CHECKCANAL,cadena,strlen(CHECKCANAL))==0){
canal=tratarCanal(cadena);
printf("CANAL: %d\n",canal);
}
else if (strncmp(CHECKQUALITY,cadena,strlen(CHECKCANAL))==0){
calidad=tratarCalidad(cadena);
printf("CALIDAD: %f",calidad);
}
else if(strncmp(CHECKESSID,cadena,strlen(CHECKESSID))==0){
essid=tratarEssid(cadena);
printf("ESSID: %s\n",essid);
}
}
return 0;
}
So I know that my problem is in the conditionals made to filterig and treating the useful strings, just I don't know why the strncmp doesn't work properly (It should compare the beginning of the line with content of the String, or that's the idea) and thus, the functions don't work properly (Maybe I messed up in the functions as well...). Is there any other chance for treating the strings I receive correctly??
The output of the printf of the char[] cadena is just like this
Channel:11
Frequency:2.462 GH
z (Channel 11)
Quality=57/70 Sig
nal level=-53 dBm
ESSID:"eduroam"
And I should be able to extract from there the ESSID, Quality and Channel.
Thanks for any idea/suggestion/help received.
use strtok() on cadena[] to divide the string into tokens as,
token[0]=strtok(cadena,"\n") //considering the output you gave each date is in newline
token[1]=strtok(NULL,"\n")
token[2]=strtok(NULL,"\n")
token[3]=strtok(NULL,"\n")
token[4]=strtok(NULL,"\n")
token[5]=strtok(NULL,"\n")
then use sscanf() to get the required data from the token as,
sscanf(token[5],"ESSID:%s",ESSID);
sscanf(token[3],"Quality=%d/%d",&q1,&q2 ) //quality=q1/q2
sscanf(token[0],"Channel:%d",&channel)
this will give the required values from the string cadena[].
Your strncpy function calls don't add the terminator to the strings you copy to. Besides, they are to small to contain the terminator.
That means that when you call functions such as atoi on an unterminated string it will cause undefined behavior, as the function continues beyond the end of the allocated memory.
So I have a program which takes a command line argument from the user and uses atoi to convert it to a number. It all works fine until the number that is passed from the command line is more than 2048.
Here is the simple program:
int no_of_elements_per_thread = 0;
int main(int argc, char* argv[])
{
int status;
void* thread_arg;
void* res;
int i = 0;
//initialize
no_of_elements_per_thread = atoi(argv[1]);
return 0;
}
When I run the program for different values the output is as follows:
[adeb1][open-19][~/pre2] ./pre2 2098
Segmentation fault
with smaller values:
[adeb1][open-19][~/pre2] ./pre2 210
[adeb1][open-19][~/pre2]
Interestingly if I try to do a printf with %s without doing atoi I still get segmentation fault as well with argv[1]. So it seems argv[1] is giving problem with values higher than 2048.
I am using gcc in linux if that matters.
Where is your declaration of atoi? Without #include <stdlib.h>, I would assume there is none.
You may also want to ensure argc > 1 before using argv[1].