#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.
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>
int main()
{
char str[7];
scanf("%s",&str);
for(i=0; i<7; i++)
{
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
}
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
return 0;
}
I'm confused about pointer of C Array because of Array with String.
Actually I want to save each character for single line input.
It is worked but I found something strange...
The main issue is &str and &str[0] have same address value.
But str have String Value with %s..
str[0] have Char Value with %c..
I used str with %c then it has first two numbers of str's address.
What is going on in Array..?
Where is real address for Stirng value??
And how can scanf("%s",&str) distribute String to each char array space?
Input : 123456789
62fe40(6487616) : 1
62fe41(6487617) : 2
62fe42(6487618) : 3
62fe43(6487619) : 4
62fe44(6487620) : 5
62fe45(6487621) : 6
62fe46(6487622) : 7
62fe40(6487616) : # 123456789
This is result window of my code.
You are confused because the string and the array are the same thing. - In the memory there are only data (and pointers to that data)
When you allocate an integer or a buffer for a string you reserve some of this memory. Strings in c is defined as a sequence of bytes terminated by one byte with the value 0 - The length is not known. With the fix length array you have a known size to work with.
The real value to the string is the pointer to the first character.
When you print with %c it expects a char - str[0] not the pointer - When you print with %s it expects a pointer to a sequence of chars.
printf("\n\n%x(%d) : %c or %s",&str, &str, str[0], str);
What is different between array String and common array in C?
An array is a contiguous sequence of objects of one type.1
A string is a contiguous sequence of characters terminated by the first null character.2 So a string is simply an array of characters where we mark the end by putting a character with value zero. (Often, strings are temporarily held in larger arrays that have more elements after the null character.)
So every string is an array. A string is simply an array with two extra properties: Its elements are characters, and a zero marks the end.
&str and &str[0] have same address value.
&str is the address of the array. &str[0] is the address of the first element.
These are the same place in memory, because the first element starts in the same place the array does. So, when you print them or examine them, they will often appear the same. (Addresses can have different representations, the same way you might write “200” or “two hundred” or “2•102” for the same number. So the same address might sometimes look different. In most modern systems, an address is just a simple number for a place in memory, and you will not see differences. But it can happen.)
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
This is not a correct way to print addresses. To print an address properly, convert it to void * and use %p3:
printf("%p(%p) : %c\n", (void *) &str[i], (void *) &str[i], str[i]);
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
…
I used str with %c then it has first two numbers of str's address.
In the above printf, the third conversion specification is %c, and the corresponding argument is str. %c is intended to be used for a character,4 but you are passing it an argument that is a pointer. What may have happened here is that printf used the pointer you passed it as if it were an int. Then printf may have used a part of that int as if it were a character and printed that. So you saw part of the address shown as a character. However, it is a bit unclear when you write “it has the first two numbers of str's address”. You could show the exact output to clarify that.
Although printf may have used the pointer as if it were an int, the behavior for this is not defined by the C standard. Passing the wrong type for a printf conversion is improper, and other results can occur, including the program printing garbage or crashing.
And how can scanf("%s",&str) distribute String to each char array space?
The proper way to pass str to scanf for %s is to pass the address of the first character, &str[0]. C has a special rule for arrays like str: If an array is used in an expression other than as the operand of sizeof or the address-of operator &, it is converted to a pointer to its first element.5 So, you can use scanf("%s", str), and it will be the same as scanf("%s", &str[0]).
However, when you use scanf("%s",&str), you are passing the address of the array instead of the address of the first character. Although these are the same location, they are different types. Recall that two different types of pointers to the same address might have different representations. Because scanf does not have knowledge of the actual argument type you pass it, it must rely on the conversion specifier. %s tells scanf to expect a pointer to a character.6 Passing it a pointer to an array is improper.
C has this rule because some machines have different types of pointers, and some systems might pass different types of pointers in different ways. Nonetheless, often code that passes &str instead of str behaves as the author desired because the C implementation uses the same representation for both pointers. So scanf may actually receive the pointer value that it needs to make %s work.7
Footnotes
1 C 2018 6.2.5 20. (This means the information comes from the 2018 version of the C standard, ISO/IEC 9899, Information technology—Programming Languages—C, clause 6.2.5, paragraph 20.)
2 C 2018 7.1.1 1. Note that the terminating null character is considered to be a part of the string, although it is not counted by the strlen function.
3 C 2018 7.21.6.1 8.
4 Technically, the argument should have type int, and printf converts it to unsigned char and prints the character with that code. C 2018 7.21.6.1 8.
5 C 2018 6.3.2.1 3. A string literal used to initialize an array, as in char x[] = "Hello";, is also not converted to a pointer.
6 C 2018 7.21.6.2 12.
7 Even if a C implementation uses the same representations for different types of pointers, that does not guarantee that using one pointer type where another is required will work. When a compiler optimizes a program, it relies on the program’s author having obeyed the rules, and the optimizations may change the program in ways that would not break a program that followed the rules but that do break a program that breaks the rules.
String is only some kind of the shorthand of the zero terminated char array. So there is no difference between the string and the "normal" array.
Where is real address for Stirng value??
Arrays are not pointers and they only decay to pointers. So there is no physical space in the memory where the address of the first element of the array is stored.
The main issue is &str and &str[0] have same address value.
It is not the issue - array is the chunk of memory. So the address of this chunk is the same as the address of its first element. The types are different.
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);
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.
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"