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.
Related
I'm making a program in which I need to first convert an integer to a string (char array) for that I used itoa() function which is working fine, after that I want to also concate it to a string, but it's not working and giving me following error:
Process returned -1073741819 (0xC0000005)
My Code:
int main(int argc, char *argv[]) {
char *scoreText = "Score: ";
char *msg;
int num = 1888;
itoa(num,msg,10);
printf("%s\n", msg);
printf("%s\n", scoreText);
strcat(scoreText, msg);
printf("%s\n", scoreText);
}
0xC0000005 is basically the Windows variant of a segmentation violation (usually caused by trying to use memory you shouldn't be using).
One of your problems lies here, with the code:
char *msg;
This creates a pointer to memory but does not actually allocate any memory for the pointer to point to. As it's an object with automatic storage duration, it will contain some arbitrary value, which is likely to be pointing somewhere other than you need.
What you should do instead is something like:
char msg[100];
which will both allocate 100 bytes for the buffer and ensure that the identifier msg points to that buffer.
Another problem is:
char *scoreText = "Score: ";
strcat(scoreText, msg);
The first line creates a character pointer and points it at the first character of the string literal "Score: ". It is undefined behaviour to attempt to modify string literals (such as by appending a string to them). To fix that issue, you have to have memory that is allowed to be modified, such as with:
char scoreText[200] = "Score: ";
This effectively gives you a 200-byte buffer initially populated with the string (as opposed to a pointer to the string literal), to which you can safely append your (up to) 100-byte msg string. It's effectively the same as
char scoreText[200];
strcpy(scoreText, "Score: ");
And, just one final point. You should be aware that itoa is not standard C but the way you're using it can be easily done with:
sprintf(msg, "%d", num);
Final working code below, though no doubt more improvements could be made:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char scoreText[200] = "Score: ";
char msg[100];
int num = 1888;
sprintf(msg, "%d", num);
printf("%s\n", msg);
printf("%s\n", scoreText);
strcat(scoreText, msg);
printf("%s\n", scoreText);
}
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 3 years ago.
I'm learning pointers in C, using Linux. I'm trying to use the strcat function, but it doesn't work and I don't understand why.
I'm passing a username to the main as an argument because I need to concatenate and put a number 1 in the first position of this username. For example if the I got as argument username123 I need to convert this to 1username123
I got this code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char *finalUser;
userTemp = argv[1]; //I got the argument passed from terminal
finalUser = "1";
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
The code compiles, but I got a segmentation fault error and doesn't know why. Can you please help me going to the right direction?
It is undefined behaviour in C to attempt to modify a string literal (like "1"). Often, these are stored in non-modifiable memory to allow for certain optimisations.
Let's leave aside for the moment the fact that your entire program can be replaced with:
#include <stdio.h>
int main(int argc, char *argv[]){
printf("User: 1%s\n", (argc > 1) ? argv[1] : "");
return 0;
}
The way you ensure you have enough space is to create a buffer big enough to hold whatever you want to do. For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
// Check args provded.
if (argc < 2) {
puts("User: 1");
return 0;
}
// Allocate enough memory ('1' + arg + '\0') and check it worked.
char *buff = malloc(strlen(argv[1]) + 2);
if (buff == NULL) {
fprintf(stderr, "No memory\n");
return 1;
}
// Place data into memory and print.
strcpy(buff, "1");
strcat(buff, argv[1]);
printf("User: %s\n", buff);
// Free memory and return.
free(buff);
return 0;
}
What you shouldn't do is to allocate a fixed size buffer and blindly copy in the data provided by a user. That's how the vast majority of security problems occur, by people overwriting buffers with unexpected data.
I'm trying to use the strcat function, but it doesn't work and I don't understand why.
For starters, you really shouldn't use strcat(). Use strlcat() instead. The "l" version of this and other functions take an extra parameter that let you tell the function how large the destination buffer is, so that the function can avoid writing past the end of the buffer. strcat() doesn't have that parameter, so it relies on you to make sure the buffer is large enough to contain both strings. This is a common source of security problems in C code. The "l" version also makes sure that the resulting string is null-terminated.
The code compiles, but I got a segmentation fault error and doesn't know why.
Here's the prototype for the function: char *strcat( char *dest, const char *src );
Now, you're calling that essentially like this: strcat("1", someString);. That is, you're trying to append someString to "1", which is a string constant. There's no extra room in "1" for whatever string is in someString, and because you're using a function that will happily write past the end of the destination buffer, your code is effectively writing over whatever happens to be in memory next to that string constant.
To fix the problem, you should:
Switch to strlcat().
Use malloc() or some other means to allocate a destination buffer large enough to hold both strings.
Unlike in other languages there is no real string type in C.
You want this:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char finalUser[100]; // finalUser can contain at most 99 characters
userTemp = argv[1]; //I got the argument passed from terminal
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
or even simpler:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
char finalUser[100]; // finalUser can contain at most 99 characters
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, argv[1]); //To concatenate argv[1] to finalUser
printf("User: %s\n",finalUser);
return 0;
}
Disclaimer: for the sake of brevity this code contains a fixed size buffer and no check for buffer overflow is done here.
The chapter dealing with strings in your C text book should cover this.
BTW you also should check if the program is invoked with an argument:
int main(int argc, char *arg[]){
if (argc != 2)
{
printf("you need to provide a command line argument\n");
return 1;
}
...
You're missing some fundamentals about C.
finalUser = "1";
This is created in "read-only" memory. You cannot mutate this. The first argument of strcat requires memory allocated for mutation, e.g.
char finalUser[32];
finalUser[0] = '1';
I expected to get errors in following code, but I did not. I did not use & sign. Also I am editing array of chars.
#include <stdio.h>
int main()
{
char name[10] ="yasser";
printf("%s\n",name);
// there is no error ,
// trying to edit array of chars,
// also did not use & sign.
scanf("%s",name);
// did not use strcpy function also.
printf("%s\n",name);
return 0;
}
I expected to get errors in following code, but I did not.I did not use & sign.
scanf("%s",name);
That's totally ok as name is already the address of the character array.
It sounds like you have several questions:
calling scanf("%s", name) should have given an error, since %s expects a pointer and name is an array? But as others have explained, when you use an array in an expression like this, what you always get (automatically) is a pointer to the array's first element, just as if you had written scanf("%s", &name[0]).
Having scanf write into name should have given an error, since name was initialized with a string constant? Well, that's how it was initialized, but name really is an array, so you're free to write to it (as long as you don't write more than 10 characters into it, of course). See more on this below.
Characters got copied around, even though you didn't call strcpy? No real surprise, there. Again, scanf just wrote into your array.
Let's take a slightly closer look at what you did write, and what you didn't write.
When you declare and initialize an array of char, it's completely different than when you declare and initialize a pointer to char. When you wrote
char name[10] = "yasser";
what the compiler did for you was sort of as if you had written
char name[10];
strcpy(name, "yasser");
That is, the compiler arranges to initialize the contents of the array with the characters from the string constant, but what you get is an ordinary, writable array (not an unwritable, constant string constant).
If, on the other hand, you had written
char *namep = "yasser";
scanf("%s", namep);
you would have gotten the problems you expected. In this case, namep is a pointer, not an array. It's initialized to point to the string constant "yasser", which is not writable. When scanf tried to write to this memory, you probably would have gotten an error.
When you pass arrays to functions in C, they decay to pointers to the first item.
Therefore for:
char name[] ="yasser";
scanf("%s", name) is the same as scanf("%s", &name[0]) and either of those invocations should send shivers down your spine, because unless you control what's on your stdin (which you usually don't), you're reading a potentially very long string into a limited buffer, which is a segmentation fault waiting to happen (or worse, undefined behavior).
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
char *myName = (char *) calloc(10, sizeof(char));
*(myName)='K'; *(myName+1)='h'; *(myName+2)='a'; *(myName+3)='l'; *(myName+4)='i'; *(myName+5)='d';
printf("%s\n",myName);
scanf("%s",myName);
printf("%s\n",myName);
return (EXIT_SUCCESS);
}
#include <stdio.h>
#include <string.h>
int main()//fonction principale
{
char name[10] ="yasser";
int longeur=0;
printf("%s\n",name);
scanf("%s",name);
longeur = strlen(name);
for (int i=0;i<longeur;i++) {
printf("%c",*(name+i));
}
return 0;}
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
I have the passed argument argv[1] in my C program, and I want to convert that string into a character array. How may I do this?
int main(int argc, char* argv[])
{
char c [] = argv[1]; // This is what I want to do...
}
EDIT:
What I'm trying to do is get certain characters from argv[1] and check if they are numbers. So, ideally, I would do something like:
int a = argv[1][2]
But this just runs into another problem - how can I check the type of a variable in C?
First of all, it already is a character array, NULL-terminated. You can simply choose to make another pointer to it, by saying char *c = argv[1];, or you can copy the entire string (null-terminator and all) into another array using the strcpy(char *destination, char *source)function http://www.cplusplus.com/reference/clibrary/cstring/strcpy/ like this:
char c[BUFFER]; //This has to be big enough to hold length + 1
strcpy(c, argv[1]);
Either approach is valid.
You can treat argv[1] as though it were an array of char (i.e., you can subscript it as argv[1][i]). You can pass it as an argument to any function that doesn't try to modify it (e.g., printf, strtol, strchr, etc.). You cannot write to it, though, so if you need to modify the contents for any reason (either directly or through a function like strtok or strcpy), you'll have to create a local copy and manipulate that.
If you are using C89 or earlier, use this method:
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
char *c = NULL;
if (argc >= 2)
{
c = malloc(strlen(argv[1]) + 1);
strcpy(c, argv[1]);
}
/**
* Do stuff with c
*/
free(c);
return 0;
}
If you are using C99, you can use a VLA:
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2)
return 0;
size_t len = strlen(argv[1]);
char c[len+1];
strcpy(c, argv[1]);
/**
* do stuff with c
*/
return 0;
}
Just remember a few things:
The type of argv is char **, not char *[N]; similarly, the type of argv[i] is char *, not char [M]. In most circumstances it doesn't matter; you can use a subscript operator on a pointer as though it were an array (array subscripting is defined in terms of pointer arithmetic), but remember that pointers and arrays are not the same thing and are not always interchangeable;
The value of argv[argc] is always NULL;
Except when it is the operand of the sizeof or unary & operators or is a string literal being used as an initializer in a declaration, an expression of array type is converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the location of the first element;
C doesn't have a string data type as such; strings are represented as 0-terminated sequences of char. String literals such as "hello" are stored in such a way that they exist over the lifetime of the program, and you can access them via a pointer value; attempting to modify them results in undefined behavior (i.e., don't do that).
argv[1][2] is of type char, always (<pedantry>accessing it causes undefined behavior if there are less than two arguments or if the length of the second argument is less than two - so its questionable whether it has a type in those cases</pedantry>). The character itself may represent a number however, and to check that, use isdigit() from header <ctypes.h>
#include <ctypes.h>
...
if (argc > 1) {
int digits = 0;
for (int i = 0, len = strlen(argv[1]); i < len; ++i)
if (isdigit(argv[1][i]))
digits++;
printf("Digits in %s: %d\n", argv[1], digits);
}
Technically, argv[1] is already a character array. There really isn't such a thing as a "string" in standard C.
What do you want to do with it? Do you just want a copy of it? In that case, you'd need to malloc some space for a new character array and then use "strcpy" to copy from argv[1] into your character array.