Related
I'm asking the user which environment variable he want to know and then I scan it with scanf. But it doesnt work for me. Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
char *value;
char input;
printf("Which variable do you want?\n");
scanf("%s", input);
value = getenv(input);
printf("%s", value);
}
The compiler says:
"Function argument assignment between types "const char*" and "char" ist not allowed"
So i tried to change the input variable to: char const *input
Now there is no compiler error, but when I submit a name, for example "USER", I get a "Segmentation fault (core dumped)" error.
The warning is because here
value = getenv(input);
you pass a char to getenv(), which has the prototype:
char *getenv(const char *name);
Define input as a char array like:
char input[256];
printf("Which variable do you want?\n");
scanf("%255s", input); //specify the width to avoid buffer overflow
Or, you can use dynamically memory allocation (using malloc) if you think 256 is not big enough for your purposes.
When you defined char *input; you satisfy the compiler because your syntax is valid: when calling scanf("%s", input); you are saying you want a string and it should get placed wherever input is.
The problem is input isn't anywhere (initialized) yet... where it points is undefined at the moment; before using any pointer you must make it point somewhere that is valid (and large enough to hold whatever you intend to put there).
There are a few ways you can solve this, but perhaps the easiest is to decide how large the input needs to be and declare a character array, such as: char input[512];. Be aware that this is problematic because if the input exceeds your buffer you will overwrite other memory... but this should get you moving forward for now.
char is a single char.
char *input declares a variable which hold a pointer to a character, but there is no memory for the data. In C, this is a correct behavior. However, sscanf expects that you actually pass a pointer which points to allocated memory (please consider that the function does not return any pointer, so it has no chance of allocating memory for you).
So between declaration and use, please use malloc to allocate memory.
My compiler (clang) shows this message:
11:17:warning: format specifies type 'char *' but the argument has
type 'char (*)[0]' [-Wformat]
scanf("%s", &name);
~~ ^~~~~
1 warning generated.
from the following code (greetings program):
/*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[0];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", &name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
What is actually going on, and how can I fix it?
In order to understand this, you have to understand what scanf is doing. scanf in this case is reading a string from stdin, and placing it into a buffer that you give it. It does not allocate that space for you, or detect overflow. You need to allocate sufficient space for your string. As it stands now, you are allocating zero space for your string, so everything is an overflow. This is a major bug.
Say instead of char[0], you did char[40], as another user suggests.What if the user of your program writes more than 40 characters? This results in undefined behavior. Essentially, it will write to memory you don't want it to write to. It might cause a segfault, it might result in crucial memory getting overwritten, or it might happen to work. This is a weakness of scanf. Look into fgets. You tell it the size of your buffer, and input will be truncated to fit.
Of course, that has nothing to do with your warning. You're getting a warning because referring to the name of an array is the same as referring to a pointer to its first element, i.e. name <==> &(name[0]). Taking a pointer to this is like taking a pointer to a pointer, i.e. &name <==> &&(name[0]). Since scanf is looking for an argument of type char*, and it's getting a pointer to that, the type checker complains.
Your code exhibits "undefined behavior." This means anything could happen. Anything.
You are passing a zero-length array to scanf(). Also, you are not passing the array length in the format string. This results in a buffer overflow vulnerability (always, in the case of a zero-length target array).
You need something like this:
char name[51];
scanf("%50s", name);
Note the %50s now specifies the size of the target array (less one, to leave room for the null terminator!), which avoids buffer overflow. You still need to check the return value of scanf(), and whether the input name is actually too long (you wouldn't want to truncate the user's input without telling them).
If you're on Linux, check out the tool called valgrind. It is a runtime memory error detector (among other things), and can sometimes catch errors like this for you (and much less obvious ones, which is the main point). It's indispensable for many C programmers.
Just change this:
scanf("%s", &name);
to:
scanf("%39s", name);
and this:
char name[0];
to:
char name[40];
Also to you have to end it with a '\0' with:
name[39] = '\0';
Depending on how robust you want this to be you will want to reconsider the approach. I guess the first thing is whether you understand the type you are using when declaring char name[ 0 ]. this is a 'zero-sized' array of byte-sized characters. This is a confusing thing and it wouldn't surprise me if its behaviour differs across compilers...
The actual warning being complained by the compiler is that the type doesn't match. If you take the address of the first character in the array you can get rid of that (i.e. use &( name[ 0 ] ) in the scanf call). The address of name is its location on the stack - it just so happens that the array implementation uses that same location to store the array data, and name is treated differently by the compiler when used on its own so that the address of an array is the same as the address of its first element...
Using char name[ 0 ] leaves you open to causing memory corruption because there is nowhere for the string to be read, and implementation details may just luck out and allow this to work. One simple way to fix this is to replace 0 with a meaningful number which you take to the maximum length of the input string. Say 32 so that you have char name[ 32 ] instead... however this doesn't handle the case of an even longer string.
Since we live in a world of lots of memory and large stacks you can probably do char name[ 4096 ] and use 4KB of memory for the buffer and that will be absolutely fine for real world usage.
Now... if you want to be a little anal and handle pathological cases, like a user leaning on some keys whilst asleep for hours before pressing enter and adding some enormous 8000 character long string there are a few ways to handle that too with 'dynamic memory allocation', but that might be a bit beyond the scope of this answer.
As an aside, from what I understand char foo[ 0 ] is intentionally valid - it may have originated as a hack and has a confusing type, but is not uncommonly relied on for an old trick to create variable sized structs as described in this page from the GCC online docs
char name[0]; ---> char name[100];
/* You need to allocate some memory to store the name */
2.scanf("%s", &name);----> scanf("%s", name);
/* scanf takes char* as an argument so you need to pass string name only. */
i don't think that scanf("%(length - 1)s", name); is needed.
Because %s is used to reads a string. This will stop on the first whitespace character reached, or at the specified field width (e.g. "%39s"), whichever comes first.
except these don't tend to be used as often. You, of course, may use them as often as you wish!
/
*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[100];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
Because the correct way is
scanf("%s", name);
/* ^ no ampersand
and what is
char name[0];
you should specify a non-zero length and use it for scanf length specifier
scanf("%(length - 1)s", name);
/* ^ sunstitite with the value */
there were several problems with the OPs posted code
the following fixes most of them
I includd comments to indicate where the problems are
int main ()
{
//char name[0]; // this did not allow any room for the name
char name[100] = {'\0'}; // declare a 100 byte buffer and init to all '\0'
printf("-------------------\n");
printf("Write your name:, max 99 char \n"); // 99 allows room for nul termination byte
printf("-------------------\n");
//scanf("%s", &name); // this has no limit on length of input string so can overrun buffer
if( 1 == scanf("%99s", name) ) // 1) always check returned value from I/O functions
// 2) no '&' before 'name' because
// arrays degrade to pointer to array when variable
// name is used
// 3) placed max size limit on format conversion string
// so input buffer 'name' cannot be overflowed
{ // then scanf failed
perror( "scanf failed for name" );
return(-1); // indicate error
}
// implied else, scanf successful
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
return(0); // indicate success
} // end function: main
You are reading a "string", thus the correct way is:
scanf("%s", name);
Why does the compiler complain? When you provide an argument in scanf, you provide the memory location of the variable. For example:
int x;
scanf("%d", &x);
&x is int *, i.e., a pointer to an integer, so x will get the correct value.
When you read a string, you're actually reading many char variables together. To store them, you need a char * array; well, name is char * on its own, so no need to write &name. The latter is char **, i.e., a 2-dimensional array of char.
By the way, you also need to allocate space for the characters to read. Thus, you have to write char name[20] (or any other number). You also need to provide a return 0; in your int main().
My compiler (clang) shows this message:
11:17:warning: format specifies type 'char *' but the argument has
type 'char (*)[0]' [-Wformat]
scanf("%s", &name);
~~ ^~~~~
1 warning generated.
from the following code (greetings program):
/*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[0];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", &name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
What is actually going on, and how can I fix it?
In order to understand this, you have to understand what scanf is doing. scanf in this case is reading a string from stdin, and placing it into a buffer that you give it. It does not allocate that space for you, or detect overflow. You need to allocate sufficient space for your string. As it stands now, you are allocating zero space for your string, so everything is an overflow. This is a major bug.
Say instead of char[0], you did char[40], as another user suggests.What if the user of your program writes more than 40 characters? This results in undefined behavior. Essentially, it will write to memory you don't want it to write to. It might cause a segfault, it might result in crucial memory getting overwritten, or it might happen to work. This is a weakness of scanf. Look into fgets. You tell it the size of your buffer, and input will be truncated to fit.
Of course, that has nothing to do with your warning. You're getting a warning because referring to the name of an array is the same as referring to a pointer to its first element, i.e. name <==> &(name[0]). Taking a pointer to this is like taking a pointer to a pointer, i.e. &name <==> &&(name[0]). Since scanf is looking for an argument of type char*, and it's getting a pointer to that, the type checker complains.
Your code exhibits "undefined behavior." This means anything could happen. Anything.
You are passing a zero-length array to scanf(). Also, you are not passing the array length in the format string. This results in a buffer overflow vulnerability (always, in the case of a zero-length target array).
You need something like this:
char name[51];
scanf("%50s", name);
Note the %50s now specifies the size of the target array (less one, to leave room for the null terminator!), which avoids buffer overflow. You still need to check the return value of scanf(), and whether the input name is actually too long (you wouldn't want to truncate the user's input without telling them).
If you're on Linux, check out the tool called valgrind. It is a runtime memory error detector (among other things), and can sometimes catch errors like this for you (and much less obvious ones, which is the main point). It's indispensable for many C programmers.
Just change this:
scanf("%s", &name);
to:
scanf("%39s", name);
and this:
char name[0];
to:
char name[40];
Also to you have to end it with a '\0' with:
name[39] = '\0';
Depending on how robust you want this to be you will want to reconsider the approach. I guess the first thing is whether you understand the type you are using when declaring char name[ 0 ]. this is a 'zero-sized' array of byte-sized characters. This is a confusing thing and it wouldn't surprise me if its behaviour differs across compilers...
The actual warning being complained by the compiler is that the type doesn't match. If you take the address of the first character in the array you can get rid of that (i.e. use &( name[ 0 ] ) in the scanf call). The address of name is its location on the stack - it just so happens that the array implementation uses that same location to store the array data, and name is treated differently by the compiler when used on its own so that the address of an array is the same as the address of its first element...
Using char name[ 0 ] leaves you open to causing memory corruption because there is nowhere for the string to be read, and implementation details may just luck out and allow this to work. One simple way to fix this is to replace 0 with a meaningful number which you take to the maximum length of the input string. Say 32 so that you have char name[ 32 ] instead... however this doesn't handle the case of an even longer string.
Since we live in a world of lots of memory and large stacks you can probably do char name[ 4096 ] and use 4KB of memory for the buffer and that will be absolutely fine for real world usage.
Now... if you want to be a little anal and handle pathological cases, like a user leaning on some keys whilst asleep for hours before pressing enter and adding some enormous 8000 character long string there are a few ways to handle that too with 'dynamic memory allocation', but that might be a bit beyond the scope of this answer.
As an aside, from what I understand char foo[ 0 ] is intentionally valid - it may have originated as a hack and has a confusing type, but is not uncommonly relied on for an old trick to create variable sized structs as described in this page from the GCC online docs
char name[0]; ---> char name[100];
/* You need to allocate some memory to store the name */
2.scanf("%s", &name);----> scanf("%s", name);
/* scanf takes char* as an argument so you need to pass string name only. */
i don't think that scanf("%(length - 1)s", name); is needed.
Because %s is used to reads a string. This will stop on the first whitespace character reached, or at the specified field width (e.g. "%39s"), whichever comes first.
except these don't tend to be used as often. You, of course, may use them as often as you wish!
/
*
* Program: gretting2.c
* Utility: Display a greeting with your name.
* Author: Adrián Garro.
*/
#include <stdio.h>
int main () {
char name[100];
printf("-------------------\n");
printf("Write your name: \n");
printf("-------------------\n");
scanf("%s", name);
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
}
Because the correct way is
scanf("%s", name);
/* ^ no ampersand
and what is
char name[0];
you should specify a non-zero length and use it for scanf length specifier
scanf("%(length - 1)s", name);
/* ^ sunstitite with the value */
there were several problems with the OPs posted code
the following fixes most of them
I includd comments to indicate where the problems are
int main ()
{
//char name[0]; // this did not allow any room for the name
char name[100] = {'\0'}; // declare a 100 byte buffer and init to all '\0'
printf("-------------------\n");
printf("Write your name:, max 99 char \n"); // 99 allows room for nul termination byte
printf("-------------------\n");
//scanf("%s", &name); // this has no limit on length of input string so can overrun buffer
if( 1 == scanf("%99s", name) ) // 1) always check returned value from I/O functions
// 2) no '&' before 'name' because
// arrays degrade to pointer to array when variable
// name is used
// 3) placed max size limit on format conversion string
// so input buffer 'name' cannot be overflowed
{ // then scanf failed
perror( "scanf failed for name" );
return(-1); // indicate error
}
// implied else, scanf successful
printf("------------------------------------\n");
printf("Hello %s, nice to meet you\n",name);
printf("------------------------------------\n");
return(0); // indicate success
} // end function: main
You are reading a "string", thus the correct way is:
scanf("%s", name);
Why does the compiler complain? When you provide an argument in scanf, you provide the memory location of the variable. For example:
int x;
scanf("%d", &x);
&x is int *, i.e., a pointer to an integer, so x will get the correct value.
When you read a string, you're actually reading many char variables together. To store them, you need a char * array; well, name is char * on its own, so no need to write &name. The latter is char **, i.e., a 2-dimensional array of char.
By the way, you also need to allocate space for the characters to read. Thus, you have to write char name[20] (or any other number). You also need to provide a return 0; in your int main().
After using malloc, name gets printed but after allocating memory and typing in a string, puts doesn't print the string at all, neither does printf...why is this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *name;
int size;
printf("enter the size if name below\n");
scanf("%d", &size);
name =(char*) malloc(size * sizeof(char));//since my compiler returns pointr of type void, you have specify whether (int*) or (char*)
if (name== NULL)
printf("memory allocation failed,,,\n");
printf("%s\n",name);
printf("enter name below\n");
scanf("%s", name);
printf("name is\n%s", name);
name = (char*)realloc(name, 100*sizeof(char));
if (name == NULL)
printf("failed\n");
gets(name);
getchar();
puts(name);
free(name);
return 0;
}
First things first, malloc/realloc do not return void, they return void* which is perfectly capable of being implicitly cast to any other pointer type. It's a bad idea to do so explicitly in C since it can hide certain subtle errors.
In addition, sizeof(char) is always one, you do not need to multiply by it.
Thirdly, using gets is a very bad idea since there's no way to protect against buffer overflow. There are much better ways to do user input.
As to the specific problem, I suspect it's most likely still sitting around at the getchar. gets will get a line from the user (including the newline character) but, unless you enter another character (probably a full line if it's using line-based I/O), it will seem to hang. Check this by simply hitting ENTER again after you've entered the name.
Try either fgets() or scanf() at the place of gets().It will work
The program that you have posted causes undefined behavior. This is because of
printf("%s\n",name);
There is nothing in the variable name and you are trying to print the value in the allocated memory. First you need to assign some value to name before printing it.
this program accepts user input and saved to a char array. Then creates a file and put those texts to the new file. Problem is, it can only copy the part before space.
Current Output : "how to read" --> "how"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argv, char *argc[]){
int fd;
char buffer[100];
printf("Type your text : ");
scanf("%s",&buffer);
fd=open("menew.txt",O_CREAT|O_WRONLY|O_EXCL,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
if(fd<0){
printf("file already exist!\n");
}else printf("file created!\n");
fd=write(fd,buffer,20);
if(fd<0){
printf("error on writing...\n");
}else printf("successfully written!\n");
close(fd);
return 0;
}
The problem isn't with the writing, it's with the reading -- the scanf %s conversion skips any leading whitespace, then reads and converts up to (but not including) the next white space.
You probably want to use something like fgets or the %[^\n] conversion with scanf.
Edit: I should probably also mention that when/if you use the scanset conversion (%[^\n]), you should specify the length of buffer you're reading into.
As far as the &buffer in scanf("%s", &buffer); being an error, technically it does give undefined behavior, but in reality I don't know of any implementation where it makes a real difference.
In this case, buffer was defined as an array, not a pointer. The name of an array "decays" to a pointer under many circumstances, but not when used as the operand of the address-of operator (unary &). As such, buffer and &buffer yield exactly the same result, the address of the beginning of the array.
There is still a difference though. When you use just buffer, you get a value with the type pointer to char (given that buffer is an array of char). When you use &buffer, you get a pointer of the type pointer to array of MAXLEN char.
Now, when you pass a value to scanf (a variadic function), you get undefined behavior when/if the type of the value you pass does not match the type expected by the conversion you specified. In reality, with every C compiler I've ever heard of, it'll work fine though, because the same address will be passed either way. In theory (but only in theory, AFAIK) a compiler could use some sort of "fat pointer" that included type information along with the address, so scanf would be able to detect the type mismatch. In reality, I don't know of any compiler that does anything very similar, so you won't see any difference between using just buffer and using &buffer in this case.
In other circumstances, however, the difference can be detectable. Addition and subtraction on pointers is based on the type, so (for example) array+1 and &array + 1 will yield different results:
#include <stdio.h>
int main() {
char array[10];
printf("%p %p %p\n", array, array+1, &array+1);
return 0;
}
This will print three numbers. The first number will be some arbitrary number, typically in hexadecimal. The second will be one greater than the first, and the second will be 10 greater than the first (because I defined it to be an array of 10 characters...)
At least one error:
scanf("%s",&buffer);
should be:
scanf("%s", buffer);
You were taking the address of a pointer. Probably not what you had intended.
Edit:
scanf also has the limitation described by Jerry Coffin.
Finally I found the solution!!!
Use gets(buffer); instant of scanf("%s",&buffer);