Fortran Character Input at Undefined Length
Asked Answered
K

3

0
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?

Killoran answered 15/2, 2013 at 0:56 Comment(0)
B
1

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.

Birdt answered 15/2, 2013 at 2:9 Comment(4)
You see, this is what I'm getting. CIPHER = 3 OUT = 'RWYDC€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ Those symbols are giving me undefined character /FULL_UNDEF error on compiel.Killoran
You don't define the entirety of the out variable - you only set characters from 1:len_trim(input). Perhaps put out = '' before the do loop, so that all characters in out are defined (they will be blanks).Birdt
Ah so its like initializing a variable before using it? It seems to stop the error, but now I'm tasked with the issue that if the input has a space, it cuts the rest out. IE: input = "This is the input." Only takes "this" without a space.Killoran
wait I got it, I used read (*,'(A)') thank you so much for the help!Killoran
L
1

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
Lathrope answered 4/6, 2015 at 0:17 Comment(0)
N
0

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.

Nazarius answered 15/2, 2013 at 1:49 Comment(1)
You see, this is what I'm getting. CIPHER = 3 OUT = 'RWYDC€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ Those symbols are giving me undefined character /FULL_UNDEF error on compile.Killoran

© 2022 - 2024 — McMap. All rights reserved.