I don't know why this code don't show error.
Let me know this why.
char str[10][5];
scanf("%s",&str[1]);
printf("%s",str[1]);
I think this must show error but this show only warning and normally execute.
Please tell me why this normally execute.
As discussed a few times before, the address of an array has the same numerical value as the address of its first element (which the array will decay to when passed to a function). That is, str[1] which is an array of char will decay to a pointer to char containing the same address as &str[1], which is the address of that array. And, believe it or not, the array starts with its first element so that both share the same address.
So both pointers point to some memory location inside str, that is, to valid addresses; they are typed just differently. C's weak type system tolerates the type differences. scanf will just assume from the format specifier %s that you passed a char pointer. Since the memory there is good (it's s[1] after all) you can scan into it.
Yes, it's UB but works on every platform available to mere mortals.
The values of str[1] and &str[1] are the same. But their types are not, the types are char* and char(*)[5] respectively.
The required type for %s is char*, if you pass an incompatible type, as you do, you get undefined behavior. Now since the value is the same, the program will work, but the code itself is not correct.
The value of expression
&str[1]
is equal to the value of expression
str[1]
That is the both address the same memory extent.
So you get the correct result because scanf and printf process the value according to the format specifier %s That is scanf stores characters at this memory extent appending them with terminating zero and printf outputs the characters from the same memory extent until it encounters the terminating zero. And the both expressions aboth supply the same address.
scanf and printf are functions that got variadic arguments. It means that you can pass any quantity of any arguments in it. Any faults followed by misuse of such a functions lead to undefined behaviour and therefore such functions considered unsafe.
Related
char a[] = {'A'};
printf(This is random value %c", &a[0] );
This program invokes undefined behavior, as %c is not the correct conversion specifier for an address. Use %p, and cast the argument to (void*).
Note: In case the argument is of type char*, casting is optional, but for any other type, the casting is necessary.
You are printing the address incorrectly.
%c is for printing characters. To print an address use %p and cast the pointer argument (i.e. the address) to void-pointer. Like
printf(This is random value %p", (void*)&a[0] );
The C standard does not define what is supposed to happen for your program. So in principal anything may happen and random values could be the result. No one can tell for sure what your code wil do (without having expert level knowledge of the specific system you are using).
However, on most systems your code will take 1 byte from the pointer and print it as-if it was a character. So the (likely) reason for your "random characters" is that the address of the array is different every time you start the program. And that is exactly what many systems do...
They use "Address Space Layout Randomization". This basically means that the address of things in your program (here the array) are randomly determined during program start up. The idea is to make it harder for hackers to exploit your program.
Read more here: https://en.wikipedia.org/wiki/Address_space_layout_randomization
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char first_name[10];
char last_name[10];
printf("What is your first name? >");
scanf_s("%s\n", &first_name);
printf("What is your last name? >");
scanf_s("%s\n", &last_name);
printf("Hello and welcome %s %s!\n", first_name, last_name);
return 0;
}
If I try run this program with Ctrl+F5, I am able to enter my first name, for example alex, and then my code crashes through the rest and wants to exit?
please advise of wrong doing
thanks
What we generally wish for from posters, especially those like you who are looking for debugging help, is an output of the compiler and linker warnings and errors, if any. We also recommend compiling with high warning settings, e.g. -pedantic for gcc or /W4 in Visual Studio.
Visual Studio tells me the following:
Severity Code Description Project File Line Suppression State
Warning C6064 Missing integer argument to 'scanf_s' that corresponds to conversion specifier '2'. scanf-array C:\Users\Peter\source\repos\scanf-array\scanf-array.cpp 15
Warning C6064 Missing integer argument to 'scanf_s' that corresponds to conversion specifier '2'. scanf-array C:\Users\Peter\source\repos\scanf-array\scanf-array.cpp 18
Warning C4473 'scanf_s' : not enough arguments passed for format string scanf-array C:\Users\Peter\source\repos\scanf-array\scanf-array.cpp 15
Warning C4473 'scanf_s' : not enough arguments passed for format string scanf-array C:\Users\Peter\source\repos\scanf-array\scanf-array.cpp 18
So, apparently scanf_s expects another argument. I don't know that function, so I looked it up (emphasis by me):
Unlike scanf and wscanf, scanf_s and wscanf_s require you to specify buffer sizes for some parameters. Specify the sizes for all c, C, s, S, or string control set [] parameters. The buffer size in characters is passed as an additional parameter. It immediately follows the pointer to the buffer or variable. For example, if you're reading a string, the buffer size for that string is passed as follows:
char s[10];
scanf_s("%9s", s, (unsigned)_countof(s)); // buffer size is 10, width spec. is 9
Of course you can for a test simply write 10 as the last parameter, it's just less robust in case you change the array size (which should be a define anyway). And voila, it works.
#t.niese was, by he way, right that the address operator in front of the arrays is wrong. What the function expects is the address of a char that's at the beginning of a buffer large enough to take the input; it does not expect the address of an array. The reason is that the address of an array of 10 has the type char (*)[10] while the address of an array of 20 has the type char (*)[20]; the arrays have different, unrelated types. They cannot stand in for each other e.g. in parameter declarations.
This is different in languages like Java or C# where arrays carry runtime (as opposed to compile time) information with them and can simply be passed as "array of char, it will know how long": In C and C++ this is compile time information, baked into the type, making arrays of different lengths incompatible.
C programmers and library functions like scanf use the trick to simply (by convention) pass around the address of the first character (whose type is naturally the same for all array lengths — address of char, or maybe even void!) plus, often, an additional length parameter. memcpy works that way. This trick is supported by the language: arrays "decay" or, in standard language, are "adjusted" to a pointer to their first element in most expressions, for example when they are passed as parameters. This happens precisely to aid this "address of the first element" compatibility trick.
That said, the address of the array is of course the address of its first element; that is, (intptr_t)&first_name == (intptr_t)&first_name[0] holds, so while the type of the buffer address you passed was wrong, the address itself was correct, and since scanf doesn't care about types except for its first argument, it just used it as the address of the first char, which, in fact, it was.
Another remark on the side: Don't include \n in the format, it requires the user to press enter twice here.
use std::cin instead of scanf_s .
it shows an error : error C4996: 'scanf_s': This function or variable may be unsafe
The IO functions from C library (printf*, scanf* and friends) are pretty good-old thing. Because they are power and flexible. But the cost of this is that they should be used carefully, with deep understanding what you are doing.
The main attention should be drawn on that they are variadic. That is, types of the last parameters are fully on the programmer's responsibility. This functions family is build in such a way this variadic arguments should correspond to the (mandatory) argument of format string. To be more precise: to the format specifiers in it and theirs order.
So, you specified the %s. Let's read what is written in the manual about this conversion specifier:
matches a sequence of non-whitespace characters (a string)
If width specifier is used, matches up to width or until the first
whitespace character, whichever appears first. Always stores a null
character in addition to the characters matched (so the argument array
must have room for at least width+1 characters)
Here you can read the "array" word. So, the characters array (C-string) argument should be passed to the scanf for the %s specifier. But you passed the pointer to the array. We can say: the pointer to pointer. Because an array's variable in C contains a pointer to the first array's element. The &array expression gives an address of the array variable by itself, not the array. I.e., an address in the memory where the array variable is placed. In your example, the scanf faithfully tried to put a string you entered at the address you passed -- at the place where the first_name variable stored, not at the place where the array's bytes are placed.
So, to be short, the & operators are waste in your code.
But, even you'll remove them, your code still will have chances to crash your program. Because the first_name and last_name arrays are of 10 characters long, but user can enter more than 10 symbols. In such a case, the scanf also will try to place oversized tail beyond of the arrays' storage. Most probably, this will lead to the program crash. As you can read in the quote of the %s description, the length specifier may be used with this specifier and it should refer to the target array's length. In your example, the %9s conversion specifier may be used. The last byte of the string will be filled with 0 by the scanf, so the 10th byte is reserved for this purpose.
UPDATE:
And yes, the scanf_s versions expect two arguments for one %c, %s or %[ conversion specifier -- the usual pointer and a value of type rsize_t indicating the size of the receiving array, which may be 1 when reading with a %c into a single char.
I know this question has been answered several times but am not able to make sense of the following script. I am new to C by the way.
As I get it, if an array used as a value it represents the address of first character aka pointer.
if I run this:
int main (){
char quote[] = "C is great"
printf ("The quote: %s\n",quote);
printf ("The address of quote is %p\n",quote);
printf ("Size of quote is %lu\n",sizeof(quote));
}
I get:
The quote: C is great
The address of quote is 0x7fff06fa0d90
Size of quote is 11
So my question is in all printf cases, I have used used the same variable quote, but by changing print type how does it change from value to pointer and where is the pointer representation stored because sizeof gives me length of the string.
Thanks!
The pointer representation is not stored in a designated location. It has the same "storage" as the result of 2 + 2. (Usually, this will be a register). These are called values officially in C; sometimes called rvalues for discussion purposes.
The conversion happens for both of the cases where you give quote as argument to printf. The %s or the %p tells printf whether to output a representation of the pointer received, or whether to follow that pointer and print out the characters at the other end.
The rvalue is formed whenever it is needed. The sizeof operator does not perform lvalue-to-rvalue conversion on its operand, so sizeof(quote) does not generate or do any operation on a pointer.
Array type conversion to pointer type has some exceptions.
C11: 6.3.2.1 (p3):
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue.
Note that the statement
printf ("The address of quote is %p\n",quote);
prints the address of first element of quote, not the address of quote although you will get the same address value on printing the address of quote.
Note that _Alingof is mentioned in draft is an error.
Internally, a pointer is an integer value that holds an address. So in all cases you are passing this pointer value to printf().
But the format specifier determines what printf() will do with that pointer. In one case, it reads the characters that are at the address contained in the pointer. In another case, it simply prints the pointer value.
All variables are pointers to memory locations in C. There is nothing else. The compiler keeps track of the variables by their pointers. It also keeps track of the variable type and size but these are not strict. Every variable is guaranteed to have a pointer, but type and consequently size can be changed.
The type and size is what determines what value is represented when a variable is used in your program but as far as your program is concerned, it actually has no idea what is stored at each pointer, except that the compiler has specifically written it into your compiled program.
You can use casting to override the type (even read memory out of bounds if you are not careful). If you have an array of 12 chars, you can read the values as an array of 3 ints if you want, for example.
In the case of static arrays (like your example), either when you define the size of the array or when you assign the value to the array, the compiler allocates the memory it needs.
It knows the length either because you told it explicitly in your definition (char quote[11]) or because it knows what has been stored in the array ("C is great" = 10). Since a char type variable is 1 byte, then 10 of them must be 10 bytes.
Your array is actually 11 bytes. This is because of how and what you assigned to it. In C, when the compiler finds a string literal, it automatically appends a NULL char on the end. If it didn't do this, functions like printf wouldn't know how long the string is. It wouldn't know because the size and type are not stored with the variable.
If you wrote your array as:
char quote[] = {'C',' ','i','s',' ','g','r','e','a','t'};
The compiler wouldn't know that it's a string and your array would be 10 bytes instead of 11. It might also behave strangely when you try to printf as a string in this case, since printf relies on the NULL byte to know when it reached the end of the string.
printf ("The quote: %s\n",quote);
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"
When we usually input the string, we do this:
#include <stdio.h>
int main()
{
char str[256];
scanf("%s",str);
//Other Operation
}
But, today, in programming class, one of my friends wrote scanf line like this:
scanf("%s",&str);
and it pass the compilation, and works.
The question is, I'd like to know if this is "legal" in C or not, or just an undefined behavior?
It's undefined behavior (because the type scanf() expects is char *, but you pass in a char (*)[256]), but it usually "works" (appears to be working) since the address of an array is often the same (regarding the numeric value of the pointer) as the address of its first element.
From the official documentation:
If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the space provided, the behavior is undefined.
(emphasis mine)
It is technically undefined behaviour. However, both methods work in practice with char arrays because the reference to str being passed to scanf() turns into a pointer to the first element, which will be equal* to a pointer to the array itself (the address of str, or &str), so the same value gets passed either way.
I'm not sure whether you've only been working with strings so far, but bear in mind that if you look at something that's not an array, it's easier to tell that your friend's method would be correct:
int myInt;
scanf("%d", &myInt);
scanf() is looking for a pointer, so you want to give it the address of your integer variable. This is because passing myInt gives it a value (currently garbage), whereas &myInt tells it where to put the value that it reads.
*Except on Win16.
Both str and &str are defined to take the value of the memory address of the first element of the array. Notwithstanding H2CO3's indication that this is undefined behaviour, this will always work in practice.