I have been trying to read an input as string from the user inside a void pointer in C. SO i wrote something like the following:
void *ptr;
ptr = calloc(100,sizeof(char));
printf("Enter the string: ");
fgets(*((char *)ptr),100,stdin);
printf("You entered ");
puts(*((char *)ptr));
I know I may not be doing it the right way, so can anybody please help me show the right way of taking a string input in a void pointer?
I want something as
input:- Enter the string: welcome user
output:- You entered: welcome user
Just convert the void* to a char*:
void *ptr;
ptr = calloc(100,sizeof(char));
printf("Enter the string: ");
fgets((char*)ptr,100,stdin);
printf("You entered ");
puts((char*)ptr);
fgets and puts take a pointer as first argument, so you could use (char*)ptr to convert the pointer.
If you write *((char*)ptr) you treat the void pointer as a char pointer, but also dereference it with * which will give you the first character. This is not what you want here.
You need to remove the (char *) casts. Try this:
void *ptr;
ptr = calloc(100,sizeof(char));
printf("Enter the string: ");
fgets((char *)ptr,100,stdin);
printf("You entered ");
puts((char *)ptr);
You are dereferencing the pointer when you pass it to fgets and fputs which means you pass the value of the first character in the memory location. Since you used calloc for the allocation you pass '\0' (the null character, zero).
Your ptr (and also (char *)ptr) points to some memory, i.e. its value is an address, a point in the RAM of your computer. fgets will copy chars from the console input to that memory location, byte by byte. Your expression *((char *)ptr) which you pass as parameter to fgets is, by contrast, the value stored at that location. After calloc() that value is zero, i.e. the character '\0'. Fgets thinks that's a pointer, tries to access the memory at address 0, and crashes. The same would happen with fputs, because under modern PC operating systems even a read access at "weird" addresses is not allowed for user programs. The solution is, as the others pointed out correctly, to omit the dereferencing "*".
By the way, did you not get a compiler warning? While C is not really type safe, it does have function prototypes, and most compilers warn against wrong parameter types when they are called.
What you basically want cannot be achieved due to your arguments in fgets().
As the function fgets() take three arguments
1.pointer to the first cell of memory at where to store the data.
2.No of characters to be written to memeory.
3.stream pointer,from where to read.
But what you are doing wrong is with first argument,as you are not passing a pointer to fgets().You are passing *((char *)ptr) it is of type char because of your unnecessary derefferencing.Removing external * will cure it because its type now becomes char * and you can use it as a legal argument for fgets().
Related
I am trying to printf a simple string but I am not being able to.
#include <stdio.h>
int main(){
char *word;
scanf("%s", &word);
printf("%s\n", word);
return 0;
}
When I insert the word my code breaks.
It just stops the program execution but doesn't give me any error.
What am I doing wrong?
Problem 1: you need to allocate space for your word.
Problem 2: Your scanf() syntax is incorrect for a character array.
Problem 3: scanf("%s", ...) itself is susceptible to buffer overruns.
SUGGESTED ALTERNATIVE:
#include <stdio.h>
#define MAXLEN 80
int main(){
char word[MAXLEN];
fgets(word, MAXLEN, stdin);
printf("%s", word);
return 0;
}
word needs space - i.e. memory
So change
char *word;
to
char word[1000]; // Or some other value as appropriate
And to prevent buffer overruns use
scanf("%999s", word); // 1 character for null!
BTW - Do not need &
By char* word, you are creating a pointer to the string but not actually allocating memory for the string which is causing the code to break.
You can either use malloc to dynamically allocate memory or try something like char str[len] where len is the string length.
In C, you need to manage the memory yourself.
char *word just points to a random memory address. No memory has been allocated. When you go to write to it the operation system won't let you and you get a memory access violation.
You need to allocate a specific amount of memory to store the characters, and the terminating null byte. "Strings" in C are arrays of characters, plus a null byte to end it. C doesn't know how much memory has been allocated to a variable.
char word[101];
scanf("%100s", word);
printf("%s\n", word);
That's space for 100 characters, plus the null byte. And scanf is restricted to read only 100 characters so it does not try to access someone else's memory.
Finally, word is already a pointer. No need to take its address.
word is an initialised pointer; you have provided no space into which scanf() can write.
Also &word has type char** where the %s format specifier requires a char*.
char word[32] ;
scanf("%31s", word);
printf("%s\n", word);
What am I doing wrong?
Other than in the program itself, the fundamental thing you're doing wrong is failing to compile with warnings enabled:
Why should I always enable compiler warnings?
If you were to compile your program with warnings enabled, you would get something like:
source>:5:12: warning: format '%s' expects argument of type 'char *', but argument 2
has type 'char **' [-Wformat=]
5 | scanf("%s", &word);
| ~^ ~~~~~
| | |
| | char **
| char *
See this on GodBolt.
That may not tell you what exactly the problem is, but it well direct you to where you're doing something fishy and unexpected.
try this:
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[80];
fgets(buffer, sizeof(buffer), stdin);
printf("echo %s\n", buffer);
return 0;
}
In C you need to manage memory. In the example above we allocate a buffer of 80 bytes on the stack; asked the standard library to read up to 80 characters and then generated the output.
In your code snippet, you had an uninitialised pointer and then you where giving the address of that pointer (which is a stack address) to scanf. scanf will then proceed to read into your stack... which means that it will typically overwrite the return address of your function.
try this snippet:
int main(void) {
char *buffer;
printf("%p\n", &buffer); // This prints a stack address
}
I was looking for some reference that would explain the concept of clobbering the stack by writing into it. This was the top link I could find.
https://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions
When C calls a function, it will do the following:
push arguments into the stack
call the function which results in stack pointer and return address being pushed into the stack
push into the stack space for local variables (e.g. our char *word;) in your initial example.
On x86 stack grows up (i.e. to lower addresses) so when you write into the memory region of a local variable and you didn't reserve space for what you want to write you are effectively overwriting the call stack.
It helps to have an idea of how a to program a CPU with assembly, specially stack and function call / return in order to properly understand C. It is also extremely useful even when one is using higher order languages; sooner or later one needs to understand what is going on under all those layers of abstraction.
Pointer is only the pointer and it does only hold the location of the object it points.
char *pointer;
This declaration creates the pointer which does not reference(point) anything.
You need to create an object and then assign the reference of this object to this pointer.
Examples:
char *word = malloc(100);
char array[100];
char *word = array;
To scanf a string you need to have the pointer assigned with the reference of the ocject which is large enough to accommodate this string.
char *word = malloc(100);
scanf("%s", word);
The difference between word and &word is explained here: Quick question about check allocation function algorithm (C)
As far as I know in c when using printf() we don't use &.Right?But in my programme, if I don't use it in the display function it gives me an error.Can someone explain this? Thank you
#include<stdio.h>
#define max 100
void enqueue();
char dequeue(void);
int front=-1,rear=-1,option;
char name[max][max],val;
void display(void);
void enqueue() {
printf("Enter the name of the paitent : ");
if(rear==max-1)
printf("Line is full");
else if (front==-1 && rear==-1)
front=rear=0;
else
rear++;
scanf("%s",&name[rear][rear]);
}
char dequeue(void) {
char val;
if(front==-1 || front >rear )
printf("Line is empty");
else
{
val=name[front];
front++;
if(front>rear)
front=rear=-1;
return val;
}
}
void display(void) {
int i;
if(front==-1|| front >rear)
printf("The queue is empty");
else
{
for(i=front; i<=rear; i++) {
printf("%s\t",&name[i][i]);
}
}
}
int main () {
printf("\n\n*******Medical Cneter********");
printf("\n\t1. Insert a paitent");
printf("\n\t2. Remove a paitent");
printf("\n\t3. Check Paitent list");
printf("\n\t4. Display");
printf("\n\t5. Exit");
do {
printf("\nEnter your option: ");
scanf("%d",&option);
switch(option)
{
case 1:
enqueue();
break;
case 2:
dequeue();
break;
// case 3:
case 4:
display();
break;
}
} while(option !=5);
}
If I don't use & the programme will crash. As far as I know in c when using printf() we don't use. But in my programme, if I don't use it in the display function it gives me an error.Can someone explain this? Thank you
To answer your question, let's review what the & operator does, and what types of values we need to pass to printf, and also, for comparison, what types of values we need to pass to scanf.
If you have a thing x, then the expression &x gives you a pointer to x. If x is an int, &x gives a pointer-to-int. If x is a char, &x gives pointer-to-char.
For example, if I write
int i;
int *ip;
ip = &i;
I have declared an int variable i, and a pointer-to-int variable ip. I have used the & operator to make a pointer to i, and I have stored that pointer-to-int in the variable ip. This is all fine.
As you may know, when you call scanf you always have to pass pointers to the variables which you want scanf to fill in for you. You can't write
scanf("%d %d", x, y); /* WRONG */
because that would pass the values of the variables x and y to scanf. But you don't want to pass values to scanf, you want scanf to read some values from the user, and transmit them back to you. In fact, you want scanf to write to your variables x and y. That's why you pass pointers to x and y, so that scanf can use the pointers to fill in your variables. So that's why you almost always see &'s on the arguments in scanf calls.
But none of those reasons applies to printf. When you call printf, you do want to pass ordinary values to it. You're not (usually) asking printf to pass any data back to you. So most of the printf format specifiers are defined as accepting ordinary values, not pointers-to-values. So that's why you hardly ever see &'s in printf calls.
Now, you might think of & as an operator that "converts things" to pointers, but that's not really a good way of thinking about it. As I said, given an object x, the expression &x constructs a pointer to x. It doesn't "convert" anything; it certainly doesn't "convert" x. It constructs a brand-new pointer value, pointing to x.
In the code you posted, it looks like you might have used & in an attempt to perform such a "conversion". You had an array name of type array-of-array-of-char, or a two-dimensional array of characters. You were trying to print a string with %s. You knew, or perhaps your compiler warned you, that %s needs a pointer-to-char, and you knew (or your compiler told you) that the expression name[i][i] gave a value of type char. Now, putting a & in front of name[i][i] did indeed get a value of type pointer-to-char, as %s requires, and it might even have seemed to work, but it's a pretty haphazard solution.
It's true that printf's %s needs a pointer-to-char, but it doesn't need just any pointer-to-char; it needs a pointer-to-char that points to a valid, null-terminated string. And that's why, even though %s needs a pointer, you still don't usually see &'s in printf calls. You could use & on a single character variable to get a pointer to that character, like this:
char c = 'x';
printf("%s", &c); /* WRONG */
But this is broken code, and won't work properly, because the pointer you get is not to a valid string, because there's no null termination.
In your code, you probably want to change the line
printf("%s\t",&name[i][i]);
to
printf("%s\t",name[i]);
name is a two-dimensional array of char, but since a string in C is an array of char, you can also think of name as being a (single dimensional) array of strings, and I think that's how you're trying to use it.
Similarly, I suspect you want to change the line
scanf("%s",&name[rear][rear]);
to
scanf("%s", name[rear]);
But before you say "I thought scanf always needed &!", remember, the rule is that scanf needs a pointer. And since name[i] is an array, you automatically get a pointer to its first element when you pass it to scanf (or in fact when you use it in any expression). (And this is also the reasoning behind printf("%s\t",name[i]).)
If you wanted to use an explicit &, what you want is a pointer to the beginning of the string array you want scanf to fill in, so I think you'd want
scanf("%s", &name[rear][0]);
instead of the expression you had.
(It looks like you were, probably accidentally, running your strings down the diagonal of the name array, instead of down the left edge. It's also curious that you declared the perfectly square array
char name[max][max];
that is, 100 strings of 100 characters each. It's not wrong, and it'll work, but it's curious, and it makes it easier to mix up the rows and the columns.)
`
I tried compiling your code and it seems I'm getting the error:
warning: assignment makes integer from pointer without a cast [-Wint-conversion]
val=name[front];
^
The reason is that name is a 2D array and you are assigning a pointer to a 1D array of chars to a char.
I think that in order to fully understand the problem one would have to understand how C deals with memory and pointers.
The '&' symbol means that you are taking the address of something (not to be confused with c++ references).
This means that if a function has an argument like the following:
void foo(char* bar);
and you want to pass your variable char var; to the function, you would have to call the function using the '&' symbol to explicitly tell the compiler that you want to pass the address of var as the parameter to the function.
foo(&var);
if you want to access the value of var inside function foo you would have to "dereference" the pointer so that the compiler understands that you want the value stored at the address you just passed to the function.
In order to dereference a pointer you use the '*' symbol.
char some_char_in_foo = *var;
I suggest reading up on pointers to clarify the matter further.
The %s conversion specifier in both printf and scanf expects it's corresponding argument to have type char *, and to point to the first character in a string.
Remember that in C, a string is a sequence of characters including a 0-valued terminator. Strings are stored in arrays of char (or wchar_t for "wide" strings).
Your name array can store max strings, each of which can be up to max-1 characters long, not counting the string terminator.
When an array expression is not the operand of the sizeof or unary & operators, or isn't a string literal used to initialize a character array in a declaration, the expression is implicitly converted ("decays") from type "array of char" to "pointer to char", and the value of the expression is the address of the first element.
name has type "max-element array of max-element array of char". This means that each name[i] has type "max-element array of char", which, if it's not the operand of & or sizeof, "decays" to type char *.
That's basically a long-winded way of saying that the expression max[i] is equivalent to &max[i][0]. So you can write your printf statement as
printf( "%s\t", name[i] );
Similarly, you can rewrite your scanf statement in the enqueue function as
scanf( "%s", name[i] );
although honestly, for user input it's safer to use fgets:
if ( fgets( name[i], sizeof name[i], stdin ) )
// successful input
else
// EOF or error on read
The & operator means "take the reference of". scanf modifies its arguments, therefore, you need to given a reference to the arguments you want modified. printf does not modify its arguments, therefore, you can pass its arguments by value, because it can do its job with a copy.
However, this is not a final rule, as the format string %p will print a pointer (i.e a reference). So printf might need a reference to a variable in some cases.
A more general rule would be this one: scanf takes its arguments by reference, printf takes its arguments by value.
I'm wondering why this code can work. I'm assuming that the scanf is assigning the value to the address of a pointer to a char. I know this expression is undefined but why does printf using a pointer can print the correct value?
int main() {
char* p;
p = (char*)malloc(sizeof(char));
scanf("%c", &p);
printf("%c", p);
return 0;
}
And the result is
c
c
p is a variable that holds a memory address, and memory addresses are surely longer than 1 byte. If you store a char value in this variable, the previous value (the malloc'ed memory block) will be lost. printf just treates your variable as a char variable and prints its contents. If you suspected that the char would be stored in the memory block obtained by malloc, no it wasn't.
Try this:
int main() {
char *p, *q;
p = q = (char*)malloc(sizeof(char));
scanf("%c", &p);
printf("%c\n%c\n", p, *q);
return 0;
}
With the scanf(), you are storing (rather forcibly) one byte into a variable that is more than one byte (sizeof(char *), likely 8 bytes on a 64-bit machine). With the printf(), you then read one byte (sizeof(char), always one by standard) of this variable of size sizeof(char *) (more than one byte) and print it. Your variable p is more space than is needed to store a char. Since the sizes don't line up, you're not sure which byte of p will be read by printf(). It could be the byte that scanf() wrote, or it could be garbage data. You just got lucky and printf() read the same byte that scanf() wrote.
If all this sounds a bit uncertain, it is because it involves undefined behaviour. You are using scanf() and printf() improperly, so they make no guarantees as to what will happen. In short, don't do this.
printf() and scanf() don't perform any special type checking on the source/destination given as an argument. They use fancy pointer arithmetic with the arguments on the stack to figure out where to read/write things as needed. After the compiler builds it, printf() and scanf() will not complain. Your compiler should have given you warnings that the types of the arguments given do not match the format string. If it didn't, you either have a bad/old compiler or you should enable more warnings with the command line option -Wall.
To hopefully help explain the other answers, it looks as if you were aiming to do the following - compare the differences then take another look at the other answers and see if that helps, as I'm not sure you're yet clear about what's happening in your code.
int main() {
char* p = malloc(sizeof(char));
scanf("%c", p);
printf("%c", *p);
return 0;
}
This is the code:
void main()
{ char strvek[500];
printf("Mata in ett stort tal: ");
scanf("%s", &strvek);
size_t len1 = strlen(strvek);
printf("%d",&len1);
}
The program ends up Printing the memory adress of len1. I want to store the length of the string in len1. If "hello" is entered I want to have the integer 5 for example.
There are thee issues with your code:
scanf does take addresses, but since strvek is an array, it "decays" to a pointer when passed to a function
Users can type more characters than your buffer holds for a buffer overflow, and
printf does not need an address for ints (your code has undefined behavior)
Here is how you fix the first two problem:
scanf("%499s", strvek); // Limit the size to 499 chars + '\0'; no ampersand in front of strvec
Here is how you fix the last problem:
printf("%d", len1); // No ampersand
It may be a little hard at first to remember when to use an ampersand with I/O functions. Generally, remember that scanf needs an ampersand except for strings, and printf does not need an ampersand except the %p format specifier (in which case you need to convert the pointer to void*).
Because you are printing the address of the len1 in the output.
Simply write:
printf("%d",len1);
What people have failed to mention in other answers (so far) is the reason why scanf wants you to pass addresses of values, while printf wants you to pass the values themselves.
In some sense, there's no technical reason why printf could not have been designed to take the addresses to values to print. If that were the convention, printf would simply go look up what is at that address (using the pointer dereference operator, *)...and print it.
Two things though:
That dereference is an "extra step" which is not needed; because just having a copy of the value itself is enough to transmit the information to printf. C likes to avoid extra steps when it can.
An address-based convention would prohibit using printf on literal values, which don't have addresses. You can't write printf("Value is %d", &10); and have it print Value is 10. This could be worked around by making a variable to store the value in and passing the address of the variable... but as I just said, C likes to avoid extra steps.
Yet with scanf, there is a technical reason why an address is required, and not a value. It needs to receive a place to put the data, such that the caller can look at that data later.
Think about reading in integers, for example. If you passed in an integer value of zero (instead of the address of an integer variable) and that's all scanf had to go on...how would it ever get the value it read back to you?
(In the particular example here, with an array of characters, there is a subtle issue regarding the lack of necessity of the address operator: see How come an array's address is equal to its value in C?...but ignore that and focus on the integer example for the concept. :-P)
It shall be
char strvek[500];
[...]
scanf("%s", strvek);
Even better do
scanf("%499s", strvek);
to prevent overflowing the buffer.
When scanning in a "string", that is a char array, passing to scanf() the array itself, lets the array decay to a pointer to its 1st element, which make it unnecessary to use the & (address of) operator.
To print out a size_t typed variable do:
size_t len = ...;
printf("%zu", len1);
printf("%d",&len1) prints the address while printf("%d",len1) prints the length itself. The & operator means "address of"
Why do 1, 2, and 3 work when 4 generates a segmentation fault? (See below.)
char c[10];
char* d;
1.
scanf("%s", &c);
printf("%s\n", &c);
2.
scanf("%s", c);
printf("%s\n", c);
3.
scanf("%s", &d);
printf("%s\n", &d);
4.
scanf("%s", d);
printf("%s\n", d);
Repeating the code in the question:
char c[10];
char* d;
1.
scanf("%s", &c);
printf("%s\n", &c);
This is likely to work as expected, but in fact the behavior is undefined.
scanf with a "%s" format requires an argument of type char*. &c is of type char (*)[10], i.e., it's a pointer to a char[10] array. It points to the same location in memory as the address of the 0th element of c, but it's of a different type. The same thing happens with the printf: the "%s" format tells it to expect a char* argument, but you're passing it a char(*)[10] argument.
Since scanf is a variadic function, there's no required type checking for arguments other than the format string. The compiler will (probably) happily pass the char (*)[10] value to scanf, assuming that it can handle it. And it probably can, on an implementation where all pointers have the same size, representation, and argument-passing mechanism. But, for example, a C compiler for an exotic architecture could easily make char* pointers bigger than pointers to larger types. Imagine a CPU whose native address points to, say, a 64-bit word; a char* pointer might be composed of a word pointer plus a byte offset.
2.
scanf("%s", c);
printf("%s\n", c);
This is better. c is an array, but in this context an array expression "decays" to a pointer to the array's first element -- which is exactly what scanf with a "%s" format requires. The same thing happens passing c to printf. (But there are still some problems; I'll get to that after the other examples.
3.
scanf("%s", &d);
printf("%s\n", &d);
Since d is a single char* argument, &d is of type char**, and again, you're passing arguments of the wrong type. If all pointers have the same representation (and the same argument-passing mechanism), and the input for the scanf is short enough, this might happen to "work". It treats the char* object as if it were an array of char. If char* is 4 bytes, and the input string is no more than 3 characters long, this will probably work -- as if you had used a char[4] and written the calls correctly. But it's extremely poor practice to store character strings directly into a pointer object, and there's a huge risk of writing past the end of the object, with unpredictable results. (Those unpredictable results include writing into memory that isn't being used for anything else, which could appear to work; such is the nature of undefined behavior.)
(The C standard gives special permission to treat any object as an array of characters, but in this case it's a very bad idea.)
4.
scanf("%s", d);
printf("%s\n", d);
Here the types are all correct, but unless you've initialized d to point to a sufficiently large array of char, it's likely to fail spectacularly (or, worse, appear to work "correctly", which means you've got a subtle bug that will probably show up later).
And now we get to what I mentioned above about other problems.
For example 4, I mentioned that d needs to point to a "sufficiently large" array. How large is "sufficiently large"? There's no answer to that. scanf("%s", ...) reads a whitespace-delimited sequence of characters with no upper bound on its length. If I run your program and hold down the x key, for example, I can provide an input string longer than any buffer you've provided, with unpredictable results (undefined behavior again).
The scanf function's "%s" format cannot be used safely (unless your program runs in an environment where you can control what will appear on the standard input stream).
One good way to read text input is to use fgets to read a line at a time, then use other functions to analyze the result. fgets requires you to specify the maximum length of the input; if the actual input exceeds the limit, it's truncated and left to be read by later calls. It's not quite as convenient as scanf, but it can be done safely. (And never use the gets function; like scanf("%s", ...), it cannot be used safely.)
Suggested reading:
Section 6 of the comp.lang.c FAQ does an excellent job of explaining C arrays and pointers, and how they're related (and not related). Section 12 discusses C standard I/O.
(I'm sorry this answer is so long; I didn't have time to make it shorter.)
You got undefined behavior in cases 3 and 4.
Cases one and two are the same, as both pointing to the first element in the array.
Case 3 is undefined, as you give a pointer to pointer to char when expecting pointer to char.
Case 4 is undefined, as the pointer d is not initialized.
3 works (on many platforms, and with a warning if you turn those on; technically it is undefined behavior) because you're abusing the pointer (treating &d, which is of type (char **), as (char *) and storing characters inside the memory intended for a pointer). 4 dies because the uninitialized pointer points to a random address.
The important question here is whether there is space in which to store the result.
scanf("%s", &c);
printf("%s\n", &c);
Is there storage? Yes, the address you take is that of the first element of the array. The array exists, so you can put the result there.
scanf("%s", c);
printf("%s\n", c);
Is there storage? Yes. Used like this, the array collapses into a pointer, which is passed same as above.
scanf("%s", &d);
printf("%s\n", &d);
Is there storage? Yes. It's not of the appropriate type, (char **, should be char *), but it shouldn't be any different than casting a char into a pointer type and storing it in a variable declared as a pointer. (Other answers say this is undefined behavior. I don't think it is, casting a char or any other integer type to a char * or other pointer type is well-defined, if ill-advised; show me where the standard says this is undefined.)
scanf("%s", d);
printf("%s\n", d);
Is there storage? Not that you've allocated. It could technically be the case that whatever happens to be in d points to a place in memory that won't segfault. Even if it does, it's not your memory and you could be overwriting something important, or it could change unexpectedly. You haven't told d where to find valid memory to point to, so you're playing pointer Russian roulette.