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;
}
Related
I'm trying to store the memory location of the evil variable in the ptr variable, but instead of the memory location, the variable prints out the value within the variable and not it's location. Both the ptr variable and the &evil syntax print the same result which is the value of the variable and not it's location in memory. Could someone please nudge me in the right direction, and help me determine the syntax needed to store the memory location of a string/char variable in C?
int main()
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
printf(ptr);//prints 4 C's
printf(&evil);//prints 4 C's
return 0;
}
That's normal, because the first parameter to printf is a format specifier, which is basically a char* pointing to a string. Your string will be printed as-is because it does not contain any format specifiers.
If you want to display a pointer's value as an address, use %p as a format specifier, and your pointer as subsequent parameter:
printf("%p", ptr);
However, note that your code invokes Undefined Behavior (UB) because your string is not null-terminated. Chances are it was null-terminated "out-of-luck".
Also notice that to be "correct code", cast the pointer to void* when sending it to printf, because different types of pointers may differ on certain platforms, and the C standard requires the parameter to be pointer-to-void. See this thread for more details: printf("%p") and casting to (void *)
printf("%p", (void*)ptr); // <-- C standard requires this cast, although it migh work without it on most compilers and platforms.
You need #include <stdio.h> for printf, and #include <string.h> for memset.
int main()
You can get away with this, but int main(void) is better.
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
This would be more legible if you replaced 0x43 by 'C'. They both mean the same thing (assuming an ASCII-based character set). Even better, don't repeat the size:
memset(evil, 'C', sizeof evil);
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
This sets ptr to the address of the initial (0th) element of the array object evil. This is not the same as the address of the array object itself. They're both the same location in memory, but &evil[0] and &evil are of different types.
You could also write this as:
ptr = evil;
You can't assign arrays, but an array expression is, in most contexts, implicitly converted to a pointer to the array's initial element.
The relationship between arrays and pointers in C can be confusing.
Rule 1: Arrays are not pointers.
Rule 2: Read section 6 of the comp.lang.c FAQ.
printf(ptr);//prints 4 C's
The first argument to printf should (almost) always be a string literal, the format string. If you give it the name of a char array variable, and it happens to contain % characters, Bad Things Can Happen. If you're just printing a string, you can use "%s" as the format string:
printf("%s\n", ptr);
(Note that I've added a newline so the output is displayed properly.)
Except that ptr doesn't point to a string. A string, by definition, is terminated by a null ('\0') character. Your evil array isn't. (It's possible that there just happens to be a null byte just after the array in memory. Do not depend on that.)
You can use a field width to determine how many characters to print:
printf("%.4s\n", ptr);
Or, to avoid the error-prone practice of having to write the same number multiple times:
printf("%.*s\n", (int)sizeof evil, evil);
Find a good document for printf if you want to understand that.
(Or, depending on what you're doing, maybe you should arrange for evil to be null-terminated in the first place.)
printf(&evil);//prints 4 C's
Ah, now we have some serious undefined behavior. The first argument to printf is a pointer to a format string; it's of type const char*. &evil is of type char (*)[4], a pointer to an array of 4 char elements. Your compiler should have warned you about that (the format string has a known type; the following arguments do not, so getting their types correct is up to you). If it seems to work, it's because &evil points to the same memory location as &evil[0], and different pointer types probably have the same representation on your systems, and perhaps there happens to be a stray '\0' just after the array -- perhaps preceded by some non-printable characters that you're not seeing.
If you want to print the address of your array object, use the %p format. It requires an argument of the pointer type void*, so you'll need to cast it:
printf("%p\n", (void*)&evil);
return 0;
}
Putting this all together and adding some bells and whistles:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ptr;
char evil[4];
memset(evil, 'C', sizeof evil);
ptr = &evil[0];
printf("ptr points to the character sequence \"%.*s\"\n",
(int)sizeof evil, evil);
printf("The address of evil[0] is %p\n", (void*)ptr);
printf("The address of evil is also %p\n", (void*)&evil);
return 0;
}
The output on my system is:
ptr points to the character sequence "CCCC"
The address of evil[0] is 0x7ffc060dc650
The address of evil is also 0x7ffc060dc650
Using
printf(ptr);//prints 4 C's
causes undefined behavior since the first argument to printf needs to be a null terminated string. In your case it is not.
Could someone please nudge me in the right direction
To print an address, you need to use the %p format specifier in the call to printf.
printf("%p\n", ptr);
or
printf("%p\n", &evil);
or
printf("%p\n", &evil[0]);
See printf documentation for all the ways it can be used.
if you want to see the address of a char - without all the array / pointer / decay oddness
int main()
{
char *ptr;
char evil;
evil = 4;
ptr = &evil;
printf("%p\n",(void*)ptr);
printf("%p\n",(void*)&evil);
return 0;
}
I have a very simple C program. In main, I have this operation:
int main(){
int theNumber = 9009;
printf("%s", (char *)theNumber);
}
And when I run it, it gives me a seg fault. Any idea why? Am I doing this wrong?
Expected Output
This code should convert theNumber to a string and then print it. So the output would be:
9009
Actual Output
A segmentation fault.
This is trying to print whatever is found at the address 9009. Seeing as the operating system is not giving your program access to this address (it is likely being used for something else entirely) the operating system raises a segmentation fault. Read more here: What is a segmentation fault?
If you really just wanted to print the value of the integer then use the correct printf command:
int main(){
int theNumber = 9009;
printf("%d", theNumber);
}
Note that you don't need to introduce a string here to achieve this.
Okay. Let's start by talking about what a string is in the C language. Fundamentally, it's a character pointer char * to a location in memory that stores a null terminated series of characters.
An example of this would be:
char *str = malloc(3);
str[0] = 'h';
str[1] = 'i';
str[2] = '\0';
str now contains the String "hi".
What does a type cast do?
The type casting that you are doing takes the integer 9009, and converts it to a char *. Then, since you use that pointer as a string, means that you are telling the computer that at address 9009, there is a null terminated series of bytes.
That's probably not true though, and unless you are on specialized hardware, is certainly not what you want.
How do you convert an integer to a string
We have a fairly easy mechanism to convert printf-able data to strings via snprintf().
First we need to allocate memory for the resultant string. This is a common difference in C from other languages. In C, you are very aware of the memory requirements of your data.
char str[100];
int size_used = snprintf(str, 100, "%d", 9009);
assert(size_used < 100);
Now, if size_used >= 100, then we have a problem. We overflowed our memory area. snprintf() will write as many characters as it can, but not the null terminating zero in that case.
Because that is not a casting of an int to a char. It's a casting of an int to a pointer to char. Basically, a pointer is a variable that holds a memory address. When you try to print that pointer, whose value is 9009, the function accesses the memory at that address, which probably is forbidden, and so you get the segfault.
To avoid that, you should use something like itoa function (be careful that it's not standard, so you may have to implement it yourself).
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().
I've recently tried some C-programming and stumbled upon the following problem. I'm using NetBeans 7.4 64 IDE with MinGW 32 Bit. This is a short example code which highlights my problem:
int main(void) {
unsigned short int temp;
char *pointer;
pointer = malloc(12 * sizeof(char));
printf("The pointers value is %d \n", (int)pointer);
printf("Type a short string:\n");
gets(pointer);
printf("The pointers value is %d \n", (int)pointer);
printf("Type an int: \n");
//This line changes the char pointer to an apparently random value
scanf("%d", &temp);
//Segmentation fault upon this point
printf("The pointers value is %d \n", (int)pointer);
//And here as well
free(pointer);
return (EXIT_SUCCESS);
}
Until scanf everything is fine. The string read by gets is written into the memory space pointer is pointing at. But AFTER scanf has been processed, pointer's value is changed so that pointer is pointing on any space. So not only my string's lost, but I also get segmentation faults when trying to access / free memory which doesn't belong to my program.
The value change is apparently random. Each time I'm debugging this program, the pointer's changed to another value.
I've already deduced that the unsigned short int is at fault, or rather the wrong format specifier (%d instead of %hu) in my scanf. If I either change unsigned short int to int or use %hu as specifier, everything works fine. So there's the solution.
But I'm still curious why and how the pointer's affected by this mistake. Can anyone help me there?
Your program has undefined behavior.
You need to tell scanf() that there's only room for a short integer, how else is it going to know which size to store the number as?
Change to:
scanf("%hu", &temp);
Where h means "half", i.e. short, and u is for unsigned. Your failure to use the proper format conversion specifier caused undefined behavior, in which scanf() overwrote a neighboring variable in memory.
Also, please note that gets() is deprecated due to being very dangerous: please don't use it. Use the much more well-behaved fgets() instead. And never scale an allocation by sizeof (char), that's just a very hard-to-read way of writing * 1 which adds no value.
Because in C nothing prevents you from writing beyond a particular variable's memory. Everything is just an address, knowing how many bytes after this address you can write to is up to you and not something the compiler is going to check.
a short int uses less bytes of memory than a regular int. You allocated a short int. Then you asked scanf to write a normal int. scanf wrote beyond the allocated memory, and overwrote part of char *pointer which happened to be located just after your short int. This is called undefined behavior because there is no knowing what you could be overwriting. The fact that pointer is located in memory right after temp is a coincidence.
pointer now points to an invalid memory address, and you get a segmentation fault when you try to access it.
A pointer is actually just another integer variable (a long) that stores a memory address.
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.