I start learning Fortran and I'm doing a little case test program where the user types two real numbers and selects an arithmetic operators (from + - * /). The following error appears when the user selects "*"
F6502 : read <con> - positive integer expected in repeat field
and if the user selects "/" the compiler executes the default case, and displays this message
invalid operator, thanks
the result is 0.000000E+00
The program is as follows.
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read*,oper
!print*,'donnez a,b,oper :'
! read(*,*)a,b,oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
FORTRAN input and output formatting rules are rather involved. Each input and ouptut statement has two arguments that have special meaning. For example
READ (10,"(2I10)") m,n
The first argument is a file descriptor. Here it is 10. The second argument "(2I10)" is the format specifier. If you give an asterisk (*) as a format specifier you switch on the list-directed formatting mode.
List directed input as the name suggests is controlled by the argument list of the input operator.
1. Why asterisk (*) is special in list-directed input mode?
The input list is split into one or more input records. Each input record is of the form c, k*c or k* where c is a literal constant, and k is an integer literal constant. For example,
5*1.01
as an instance of k*c scheme is interpreted as 5 copies of number 1.01
5*
is interpreted as 5 copies of null input record.
The symbol asterisk (*) has a special meaning in list-directed input mode. Some compiler runtimes would report a runtime error when they encounter asterisk without an integer constant in list-directed input, other compilers would read an asterisk. For instance GNU Fortran compiler is known for standards compliance, so its runtime would accept *. Other compiler runtimes might fail.
2. What's up with slash (/)?
A comma (,), a slash (/) and a sequence of one or more blanks ( ) are considered record separators in list-directed input mode.
There is no simple way to input a slash on its own in this mode.
3. Possible solution: specify format explicitly
What you can do to make the runtime accept a single slash or an asterisk is to leave the list-directed input mode by specifying the format explicitly:
read (*,"(A1)") oper
should let you input any single character.
Ok then the correct source code is
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read (*,"(A1)") oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
Related
Suppose I have a Fortran program like the following:
character*30 changed_string1
changed_string1="hello"
write(*,"(A)")changed_string1(1:3)
end
I would like to print the string with quotes so that I can exactly see leading and trailing spaces. How to do this?
There is no edit descriptor for characters which outputs them along with delimiters. A character variable does not have "automatic" delimiters like those which appear in a literal character constant (although may have them as content).
Which means you have to explicitly print any chosen delimiter yourself, adding them to the format or concatenating as in Vladimir F's answer.
Similarly, you can also add the delimiters to the output list (with
corresponding format change):
write (*,'(3A)') '"', string, '"'
You can even write a function which returns a "delimited string" and use the
result in the output list:
implicit none
character(50) :: string="hello"
print '(A)', delimit(string,'"')
contains
pure function delimit(str, delim) result(delimited)
character(*), intent(in) :: str, delim
character(len(str)+2*len(delim)) delimited
delimited = delim//str//delim
end function delimit
end program
The function result above could even be deferred length (character(:), allocatable :: delimited) to avoid the explicit statement of result length.
As yamajun reminds us in a comment, a connection for formatted output has a delimiter mode, which does allow quotes and apostrophes to be added automatically to the output for list-directed and namelist output (only). For example, we can control the delimiter mode for a particular data transfer statement:
write(*, *, delim='quote') string
write(*, *, delim='apostrophe') string
or for the connection as a whole:
open(unit=output_unit, delim='quote') ! output_unit from module iso_fortan_env
Don't forget that list-directed output will add that leading blank to your output, and if you have quotes or apostrophes in your character output item you will not see exactly the same representation (this could even be what you want):
use, intrinsic :: iso_fortran_env, only : output_unit
open(output_unit, delim='apostrophe')
print*, "Don't be surprised by this output"
end
Fortran 2018 doesn't allow arbitrary delimiter choice in this way, but this could still be suitable for some uses.
You can print quotes around your string. That will enable see the leading and trailing spaces.
write(*,"('''',A,'''')") changed_string1
or with the same effect
write(*,"(3A)") "'",changed_string1,"'"
(also mentioned by francescalus) that print a ' character before and afgter your string,
or you can concatenate your string with these characters and print the result
write(*,"(A)") "'"//changed_string1//"'"
I start learning Fortran and I'm doing a little case test program where the user types two real numbers and selects an arithmetic operators (from + - * /). The following error appears when the user selects "*"
F6502 : read <con> - positive integer expected in repeat field
and if the user selects "/" the compiler executes the default case, and displays this message
invalid operator, thanks
the result is 0.000000E+00
The program is as follows.
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read*,oper
!print*,'donnez a,b,oper :'
! read(*,*)a,b,oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
FORTRAN input and output formatting rules are rather involved. Each input and ouptut statement has two arguments that have special meaning. For example
READ (10,"(2I10)") m,n
The first argument is a file descriptor. Here it is 10. The second argument "(2I10)" is the format specifier. If you give an asterisk (*) as a format specifier you switch on the list-directed formatting mode.
List directed input as the name suggests is controlled by the argument list of the input operator.
1. Why asterisk (*) is special in list-directed input mode?
The input list is split into one or more input records. Each input record is of the form c, k*c or k* where c is a literal constant, and k is an integer literal constant. For example,
5*1.01
as an instance of k*c scheme is interpreted as 5 copies of number 1.01
5*
is interpreted as 5 copies of null input record.
The symbol asterisk (*) has a special meaning in list-directed input mode. Some compiler runtimes would report a runtime error when they encounter asterisk without an integer constant in list-directed input, other compilers would read an asterisk. For instance GNU Fortran compiler is known for standards compliance, so its runtime would accept *. Other compiler runtimes might fail.
2. What's up with slash (/)?
A comma (,), a slash (/) and a sequence of one or more blanks ( ) are considered record separators in list-directed input mode.
There is no simple way to input a slash on its own in this mode.
3. Possible solution: specify format explicitly
What you can do to make the runtime accept a single slash or an asterisk is to leave the list-directed input mode by specifying the format explicitly:
read (*,"(A1)") oper
should let you input any single character.
Ok then the correct source code is
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read (*,"(A1)") oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
I want to add blank space in a string. For example: name is a variable that equal to "abcxyzdefg".
Now, I want to print this string as: abc xyz defg
I used this program
program name_space
implicit none
character(len=30) :: name = "abcxyzdefg"
write(*,3) name
3 format (A3, 2X, A3, 2X, A4)
end program
I want output as:
abc xyz defg
But, I am getting by this way:
abc
You must refer to the appropriate substrings
write(*,3) name(1:3), name(4:6), name(7:)
with just doing write(*,'(A3,1X,A3,...)') name the first descriptor prints the first three characters of name and then the output list is finished, there are no more items to be printed, so the write statement terminates.
With the output statement
write(*,3) name
we are treating name as a single transfer item, processed by the A3 format. This A3 format prints the first three characters for the string.
There's no further processing that can be done which transforms the item to a desirable form.
Instead, we may want to have three different transfer items. One way is as in the answer by Vladimir F, to use individual substrings:
write(*,3) name(1:3), name(4:6), name(7:10)
write(*,3) (name(i:i+2), i=1,4,3), name(7:) ! Can use implied do if desired
We can also split name in some way to get an array (if the elements are the same length that we know). As an array, each element forms an individual output item:
write(*,3) TRANSFER(name, 'aaa', 3)
write(*,'(3A4)') split_into_chunks_of_4(name)
or we can transform the string to add spaces and then output that:
write(*,'(A)') split_into_chunks(name) ! for some suitable function
For the case of the question, Vladimir F's answer is the best approach. In other cases there are many options.
As the more general case of inserting spaces into a string hides much of the hard work, it's perhaps only fair to give an indication of an approach:
! Add spaces to a string str at the breakpoints bps
function split(str, bps)
character(*), intent(in) :: str
integer, intent(in) :: bps(:)
character(LEN(str)+SIZE(bps)) :: split
integer i
split=''
split(1:bps(1)-1) = str(1:bps(1)-1)
do i=1, SIZE(bps)-1
split(bps(i)+i:bps(i+1)-1+i) = str(bps(i):bps(i+1))
end do
split(bps(i)+SIZE(bps):) = str(bps(i):)
end function
I start learning Fortran and I'm doing a little case test program where the user types two real numbers and selects an arithmetic operators (from + - * /). The following error appears when the user selects "*"
F6502 : read <con> - positive integer expected in repeat field
and if the user selects "/" the compiler executes the default case, and displays this message
invalid operator, thanks
the result is 0.000000E+00
The program is as follows.
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read*,oper
!print*,'donnez a,b,oper :'
! read(*,*)a,b,oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
FORTRAN input and output formatting rules are rather involved. Each input and ouptut statement has two arguments that have special meaning. For example
READ (10,"(2I10)") m,n
The first argument is a file descriptor. Here it is 10. The second argument "(2I10)" is the format specifier. If you give an asterisk (*) as a format specifier you switch on the list-directed formatting mode.
List directed input as the name suggests is controlled by the argument list of the input operator.
1. Why asterisk (*) is special in list-directed input mode?
The input list is split into one or more input records. Each input record is of the form c, k*c or k* where c is a literal constant, and k is an integer literal constant. For example,
5*1.01
as an instance of k*c scheme is interpreted as 5 copies of number 1.01
5*
is interpreted as 5 copies of null input record.
The symbol asterisk (*) has a special meaning in list-directed input mode. Some compiler runtimes would report a runtime error when they encounter asterisk without an integer constant in list-directed input, other compilers would read an asterisk. For instance GNU Fortran compiler is known for standards compliance, so its runtime would accept *. Other compiler runtimes might fail.
2. What's up with slash (/)?
A comma (,), a slash (/) and a sequence of one or more blanks ( ) are considered record separators in list-directed input mode.
There is no simple way to input a slash on its own in this mode.
3. Possible solution: specify format explicitly
What you can do to make the runtime accept a single slash or an asterisk is to leave the list-directed input mode by specifying the format explicitly:
read (*,"(A1)") oper
should let you input any single character.
Ok then the correct source code is
program operateur
implicit none
CHARACTER(LEN=1) :: oper
real::a,b,res
print*,'Give the first number a :'
read*,a
print*,'Give the second number b :'
read*,b
print*,'which operation ?'
read (*,"(A1)") oper
select case (oper)
case ('+')
res=a+b
case ('-')
res=a-b
case ('*')
res=a*b
case ('/')
res=a/b
case default
print*, "Invalid Operator, thanks"
end select
print*,'the result is ',res
end program operateur
program Test
implicit none
character (LEN=100) :: input
character (LEN=100) :: output
print *,"Please input your message: "
read *, input
For every character, I encrypt it in Ceaser's Cipher
Calculations
print *,"This is the output: "
write (*,"(2a)") "Message = ", out
end program Test
This doesn't work entirely.
For every character in the input, I convert it using the modulo(iachar()) functions. It works up until the print, I followed the debugging, the encryption is fine.
But the issue with the output lies in LEN=100. The do loop will go through 100 times converting nonexistent characters into garbage, breaking the program at output with UNDEFINED TYPE.
So if I input "test", it will encrypt CBNC*GARBAGE-TO-100* and not output. If I define length as 4, and do it, it works. but I want to be able to do it without defining a length. Any way around this?
The read statement should pad input out to the full length of the variable (100 characters) with blanks, rather than adding "garbage". The LEN_TRIM intrinsic function will give the significant length of the variable's value - i.e. the length excluding trailing blanks. You may need to remember this significant length of the input string for when you print the output string.
(Note the rules on list directed input (indicated by the * in the read statement) can be a little surprising - a format of "(A)" may be more robust, depending on the behaviour your want.)
In terms of avoiding fixed length strings in the context of reading input - Fortran 2003 introduces deferred length character, which greatly helps here. Otherwise see Reading a character string of unknown length for Fortran 95 possibilities. One complication is that you are reading from the console, so the backspace statement may not work. The work around to that follows a similar approach to that linked, but necessitates piecewise building the input string into an allocatable array of character at the same time as the input record length is being determined. Sequence association is then used to convert that array into a scalar of the right length. Comment or ask again if you want more details.
The following code reads a user input string of unspecified length. Be aware that it requires a compiler that supports deferred-length character strings: character(len = :). Deferred-length character strings were introduced in Fortran 2003.
program test
use iso_fortran_env, only : IOSTAT_EOR
implicit none
integer :: io_number
character(len = 1) :: buffer
character(len = :), allocatable :: input, output
input = ""
print *, "Please input your message."
do
read(unit = *, fmt = '(a)', advance = "no", iostat = io_number) buffer
select case (io_number)
case(0)
input = input // buffer
case(IOSTAT_EOR)
exit
end select
end do
allocate(character(len=(len(input))) :: output)
! Now use "input" and "output" with the ciphering subroutine/function.
end program test
Explanation
The idea is to read in a single character at a time while looking for the end-of-record (eor) condition. The eor condition is caused by the user pressing the "return" key. The "iostat" option can be used to look for eor. The value returned by "iostat" is equal to the integer constant "IOSTAT_EOR" located in the the module "iso_fortran_env":
use iso_fortran_env, only : IOSTAT_EOR
We declare a deferred-length character string to grab user input of an unknown length:
character(len = :), allocatable :: input
In the "read" statement, "advance = 'no'" allows a few characters to be read in at a time. The size of "buffer" determines the number of characters to be read in (1 in our case).
read(unit = *, fmt = '(a)', advance = "no", iostat = io_number) buffer
If "iostat" returns a "0", then there were no errors and no eor. In this case the "buffer" character should be added to the "input" string. Ultimately this step allocates a "new" input that has the size of the "old" input + the buffer character. The newly allocated input contains the characters from the old input + the buffer character.
select case (io_number)
case(0)
input = input // buffer
If "iostat" returns an eor value, then exit the do loop.
case(IOSTAT_EOR)
exit
The standard Fortran string is fixed length, padded on the right with blanks. If your input string will never have trailing blanks the solution is easy: use the Fortran intrinsic function len_trim to find the nonblank length of the string and process only those characters. Another approach is to use a new feature, allocatable string ... this provides variable length strings. If disallowing blanks at the end of the string is acceptable, you will probably find using len_trim easier.