Example Code Using Scan/ScanFile/ScanIn
- Updated2023-02-21
- 17 minute(s) read
Example Code Using Scan/ScanFile/ScanIn
This section contains examples of program code that use Scan, ScanFile, and ScanIn from the Formatting and I/O Library. To eliminate redundancy, the examples include no error checking on I/O operations in this section except for the ASCII File to Two Integers with Error Checking example.
The examples are logically organized as shown:
String to real, skipping over non-numeric characters in the string
String to real, after finding a semicolon in the string
String to real, after finding a substring in the string
String with comma-separated ASCII numbers to real array
Scanning strings that are not null-terminated
Integer array to real array with byte swapping
Integer array that contains 1-byte integers to real array
Strings that contain binary integers to integer array
Strings that contain an IEEE-format real number to a real variable
ASCII file to two integers with error checking
Binary file to integer array, assuming a fixed number of elements
Binary file to real array, assuming a fixed number of elements
Binary file to real array, assuming a variable number of elements
Reading an integer from the standard input
Reading a string from the standard input
Reading a line from the standard input
String to Integer
char *s;
int a, n;
s = "32";
n = Scan (s, "%s>%i", &a); /* result: a = 32, n = 1 */
s = "-32";
n = Scan (s, "%s>%i", &a); /* result: a = -32, n = 1 */
s = " +32";
n = Scan (s, "%s>%i", &a); /* result: a = 32, n = 1 */
s = "x32";
n = Scan (s, "%s>%i", &a); /* result: a = ??, n = 0 */
When locating an integer in a string, Scan skips over white space characters such as spaces, tabs, linefeeds, and carriage returns. If Scan finds a non-numeric character other than a white space character, +, or - before the first numeric character, the Scan call fails. Thus, Scan fails on the x in x32. Scan leaves the value unmodified in a and returns zero, indicating that no target specifiers were satisfied.
s = "032";
n = Scan (s, "%s>%i", &a); /* result: a = 32, n = 1 */
s = "32a";
n = Scan (s, "%s>%i", &a); /* result: a = 32, n = 1 */
s = "32";
n = Scan (s, "%s>%o", &a); /* result: a = 26, n = 1 */
s = "32";
n = Scan (s, "%s>%x", &a); /* result: a = 50, n = 1 */
When you use the %i specifier, Scan interprets numeric characters as decimal, even when they might appear to be octal, as in 032, or hexadecimal, as in 32a. When you use the %o specifier, Scan always interprets the numeric characters (01234567) as octal. When you use the %x specifier, Scan always interprets the numeric characters (0123456789abcdef) as hexadecimal.
s = "32x1";
n = Scan (s, "%s>%i", &a); /* result: a = 32, n = 1 */
Scan considers the occurrence of a non-numeric character, such as the x in 32x1, to mark the end of the integer.
s = "32567";
n = Scan (s, "%s>%i[w3]", &a); /* result: a = 325, n = 1 */
The w3 modifier specifies that the function only scans the first 3 bytes of the string.
String to Short Integer
char *s;
short a;
int n;
s = "9999";
n = Scan (s, "%s>%i[b2]", &a); /* result: a = 9999, n = 1 */
s = "23417";
n = Scan (s, "%s>%o[b2]", &a); /* result: a = 9999, n = 1 */
s = "ffff";
n = Scan (s, "%s>%x[b2]", &a); /* result: a = 65535, n = 1 */
Scan extracts short integers from strings in the same way it extracts integers. The only differences are that you must use the b2 modifier and specify the target argument as a short integer. Refer to the String to Integer example earlier in this section for more information about using Scan to extract integers and short integers from strings.
String to Real
char *s;
double x;
int n;
s = "12.3";
n = Scan (s, "%s>%f", &x); /* result: x = 12.3, n = 1 */
s = "-1.23e+1";
n = Scan (s, "%s>%f", &x); /* result: x = -12.3, n = 1 */
s = "1.23e-1";
n = Scan (s, "%s>%f", &x); /* result: x = 0.123, n = 1 */
When locating a real number in a string, Scan accepts either floating-point notation or scientific notation.
s = " 12.3";
n = Scan (s, "%s>%f", &x); /* result: x = 12.3, n = 1 */
s = "p12.3";
n = Scan (s, "%s>%f", &x); /* result: x = ????, n = 0 */
When locating a real number in a string, Scan skips over white space characters. If Scan finds a non-numeric character other than a white space character, +, or - before the first numeric character, the Scan call fails. Thus, Scan fails on the p in p12.3. Scan leaves the value in x unmodified and returns zero, indicating that no target specifiers were satisfied.
s = "12.3m";
n = Scan (s, "%s>%f", &x); /* result: x = 12.3, n = 1 */
s = "12.3.4";
n = Scan (s, "%s>%f", &x); /* result: x = 12.3, n = 1 */
s = "1.23e";
n = Scan (s, "%s>%f", &x); /* result: x = ????, n = 0 */
Scan considers the occurrence of a non-numeric character, such as the m in 12.3m, to mark the end of the real number. A second decimal point also marks the end of the number. However, Scan fails on 1.23e because the value of the exponent is missing.
s = "1.2345";
n = Scan (s, "%s>%f[w4]", &x); /* result: x = 1.23, n = 1 */
The w4 modifier specifies that the function scans only the first 4 bytes of the string.
String to Integer and Real
char *s;
int a, n;
double x;
s = "32 1.23";
n = Scan (s, "%s>%i%f", &a, &x);
/* result: a = 32, x = 1.23, n = 2 */
s = "32, 1.23";
n = Scan (s, "%s>%i[x]%f", &a, &x);
/* result: a = 32, x = 1.23, n = 2 */
s = "32, 1.23";
n = Scan (s, "%s>%i%f", &a, &x);
/* result: a = 32, x = ????, n = 1 */
After each of the first two calls to Scan, a = 32, x = 1.23, and n = 2, indicating that two target specifiers were satisfied. In the second call, Scan uses the x modifier to discard the separating comma.
In the third call, a comma separator appears after the integer, but the x modifier is absent. Consequently, Scan fails when attempting to find the real number. x remains unmodified, and n = 1, indicating that only one target specifier was satisfied.
String to String
char *s;
char buf[10];
int n;
s = " abc ";
n = Scan (s, "%s>%s", buf); /* result: buf = "abc" */
s = " abc ";
n = Scan (s, "%s>%s[y]", buf); /* result: buf = " abc" */
When extracting a substring from a string, Scan skips leading spaces and tabs unless the y modifier is present.
s = "a b c; d";
n = Scan (s, "%s>%s", buf); /* result: buf = "a" */
s = "a b c; d";
n = Scan (s, "%s>%s[t59]", buf); /* result: buf = "a
b c" */
When Scan extracts a substring from a string and the t modifier is absent, Scan considers the substring to be terminated by a white space character. If you want to include embedded white space in the target string, use the t modifier to change the target string termination character. In the second call to Scan, [t59] changes the termination character to a semicolon (ASCII 59).
s = " abcdefghijklmnop";
n = Scan (s, "%s>%s[w9]", buf); /* result: buf = "abcdefghi" */
s = " abc";
n = Scan (s, "%s>%s[w9]", buf); /* result: buf = "abc "*/
s = " abc";
n = Scan (s, "%s>%s[w9q]", buf); /* result: buf = "abc" */
The w modifier can be used to prevent Scan from writing beyond the end of a target string. The width specified does not include the ASCII NUL that Scan places at the end of the target string. Therefore, the width you specify should be at least one less than the width of the target character buffer.
When you use the w modifier and the string extracted is smaller than the width specified, Scan fills the remaining bytes in the target string with blanks. However, if you also use the q modifier, ASCII NULs fill the remaining bytes.
String to Integer and String
char *s;
char buf[10];
int a, n;
s = "32abc";
n = Scan (s, "%s>%i%s", &a, buf);
/* result: a = 32, buf = "abc", n = 2 */
s = "32abc";
n = Scan (s, "%s>%i %s", &a, buf);
/* result: a = 32, buf = ?????, n = 1 */
After the first call to Scan, a = 32, buf = "abc", and n = 2. Notice there are no spaces in the format string between the two target specifiers. In the second call, there is a space between %i and %s. Consequently, Scan expects a space to occur in s immediately after the integer. Because there is no space in s, Scan fails at that point. Scan leaves buf unmodified and returns 1, indicating that only one target specifier is satisfied.
![]() |
Note Do not put spaces between specifiers in Scan, ScanFile, or ScanIn format strings. |
String to Real, Skipping over Non-Numeric Characters in the String
char *s;
double x;
int n;
s = "VOLTS = 1.2";
n = Scan (s, "%s>%s[dt#]%f", &x); /* result: x = 1.2, n = 2 */
s = "VOLTS = 1.2";
n = Scan (s, "%s[i8]>%f", &x); /* result: x = 1.2, n = 1 */
s = "VOLTS = 1.2";
n = Scan (s, "%s>VOLTS = %f", &x); /* result: x = 1.2, n = 1 */
The three different format strings represent different methods for skipping over non-numeric characters. In the first call, the format string contains two target specifiers. In the first specifier %s[dt#], the t# modifier instructs Scan to read bytes from s until it encounters a number. The d modifier tells Scan to discard the bytes because no argument corresponds to the specifier. When the Scan call succeeds, it returns 2, indicating that two target specifiers were satisfied, even though only one target argument exists.
In the second call, the source specifier %s[i8] instructs Scan to ignore the first 8 bytes of s. This method works only if the location of the number within s is always the same.
In the third call, the format string contains the non-numeric characters literally. This method works only if the non-numeric characters in s are always the same.
String to Real, After Finding a Semicolon in the String
char *s;
double x;
int n;
s = "TIME 12:45:00; 7.34";
n = Scan (s, "%s>%s[xdt59]%f", &x); /* result: x = 7.34, n = 2 */
Some programmable instruments return strings that contain headers that contain both numeric and non-numeric data and are terminated by a particular character, such as a semicolon. This example shows how you can skip such a header.
The format string contains two target specifiers. In the first specifier, %s[xdt59], the t59 modifier instructs Scan to read bytes from s until it encounters a semicolon. The d modifier indicates that Scan must discard the bytes because no argument corresponds to the specifier. The x modifier indicates that the semicolon also should be discarded.
When the Scan call succeeds, it returns 2, indicating that two target specifiers were satisfied, even though only one target argument exists.
String to Real, After Finding a Substring in the String
char *s;
double x;
int index, n;
s = "HEADER: R5 D6; DATA 3.71E+2";
index = FindPattern (s, 0, -1, "DATA", 0, 0) + 4;
n = Scan (s, "%s[i*]>%f", index, &x);
/* result: x = 371.0, n = 1 */
This example is similar to the previous one except that the portion of the string to skip is terminated by a substring DATA rather than by a single character. FindPattern finds the index where DATA begins in s. You add four to the index so that index points to the first byte after DATA. You then pass the index to Scan and match it with the asterisk (*) in the format string.
In this example, FindPattern returns 15, and index is 19. When you match index to the asterisk in the format string in the Scan call, Scan interprets the format string as %s[i19]>%f. The i19 indicates that Scan should ignore the first 19 bytes of s. Scan then extracts the real number from the remaining string, 3.71E+2, and assigns it to x. Scan returns 1, indicating that one target specifier is satisfied.
String with Comma-Separated ASCII Numbers to Real Array
char *s;
int n;
double a[5]; /* 5 8-byte real numbers */
s = "12.3, 45, 6.5, -1.3E-2, 4";
n = Scan (s, "%s>%5f[x]", a);
/* result: a[0] = 12.3, a[1] = 45.0, a[2] = 6.5, */
/* a[3] = -0.013, a[4] = 4.0, n = 1 */
The x modifier causes Scan to discard the comma separators.
Scan considers an array target to be satisfied when at least one element of the array is filled in. If the source string in this example were 12.3, only the first element of a would be filled in, the other elements would remain unmodified, and Scan would return 1.
Scanning Strings That Are Not Null-Terminated
int bd;
double x;
char s[20];
ibrd (bd, s, 15);
Scan (s, "%s[w*]>%f", ibcnt, &x);
All the previous examples assume that s is a null-terminated string. However, when reading data from programmable instruments using the GPIB/GPIB 488.2 and RS-232 Library functions, the data transferred is not null-terminated. This example uses ibrd to read up to 15 bytes from a GPIB instrument. The global variable ibcnt contains the actual number of bytes transferred. Scan uses the value in ibcnt in conjunction with the w modifier to specify the width of the source string.
For example, if ibcnt is 12, the format string is interpreted as %s[w12]>%f, causing Scan to use only the first 12 bytes of s.
The following example is an alternative method for handling strings that are not null-terminated.
int bd;
double x;
char s[20];
ibrd (bd, s, 15);
s[15] = 0; /* ASCII NUL is 0 */
Scan (s, "%s>%f", &x);
This code shows how to insert an ASCII NUL at the end of the transferred bytes. After the assignment, s is null-terminated.
Integer Array to Real Array
int ivals[100];
double dvals[100];
Scan (ivals, "%100i>%100f", dvals);
Scan converts each integer in ivals to a real number and writes the real number into dvals.
Integer Array to Real Array with Byte Swapping
int ivals[100];
double dvals[100];
Scan (ivals, "%100i[o10]>%100f", dvals);
For each integer in ivals, Scan byte-swaps the integer, converts the integer to a real number, and writes the real number into dvals.
Byte swapping is useful when a programmable instrument sends back 2-byte integers with the high byte first, followed by the low byte. When Scan reads this data into an integer array, the placement of the bytes is such that Scan interprets the high byte as the low byte. The o10 modifier specifies that Scan interprets the bytes in the opposite order.
Integer Array That Contains 1-Byte Integers to Real Array
int ivals[50]; /* 100 1-byte integers */
double dvals[100]; /* 100 8-byte real numbers */
Scan (ivals, "%100i[b1]>%100f", dvals);
Scan (ivals, "%100i[b1u]>%100f", dvals);
Sometimes, Scan uses each element in an integer array to store two 1-byte integers. This example shows how to unpack the 1-byte integers and store them in a real array. The b1 indicates that each binary integer is only 1 byte long.
The first call to Scan treats the 1-byte integers as signed values, from –128 to +127. The second call includes a u in the format string, which causes Scan to treat the 1-byte integers as unsigned values, from 0 to 255.
Strings That Contain Binary Integers to Integer Array
char s[400]; /* string containing 100 4-byte
integers */
int ivals[100]; /* 100 4-byte integers */
Scan (s, "%100i[z]>%100i", ivals);
Scan (s, "%97i[zi6]>%97i", ivals);
Sometimes Scan reads data from a programmable instrument into a character buffer even though it contains binary data. This example shows how to treat a character buffer as an integer array. The format string in each Scan call specifies that the source s contains an array of 100 integers. The z modifier indicates that the source is actually a character buffer.
In some cases, the integer data might not start at the beginning of the character buffer. For instance, the data in the buffer can begin with an ASCII header. In the second call to Scan, the i6 modifier indicates that Scan should ignore the first 6 bytes of s.
![]() |
Note When you use the i modifier in conjunction with a character buffer, the number that follows the i specifies the number of bytes within the buffer to ignore. This is true even when the z modifier also is present. However, when you use the i modifier in conjunction with an array variable, the number that follows the i indicates the number of array elements to ignore. |
Strings That Contain an IEEE-Format Real Number to a Real Variable
char s[100];
double x;
Scan (s, "%1f[z]>%f", &x);
Scan (s, "%1f[zi5]>%f", &x);
This example is similar to the previous example except that s contains a single binary real number, in IEEE format, rather than an array of binary integers. The format string in each Scan call indicates that Scan treats the source s as a one-element array of real numbers. The z modifier indicates that the source is actually a character buffer. The repetition count of 1 in the format string is required; otherwise, Scan does not accept the z modifier.
The first call to Scan assumes that the real number is at the beginning of s. The second call assumes that the real number starts at the sixth byte of s. The i5 modifier causes Scan to ignore the first 5 bytes of s.
ASCII File to Two Integers with Error Checking
int file_handle, n, a, b;
file_handle = OpenFile ("FILE.DAT", 1, 2, 1);
if (file_handle < 0) {
FmtOut ("Error opening file\n");
exit (1);
}
n = ScanFile (file_handle, "%s>%i%i", &a, &b);
if (n != 2) {
FmtOut ("Error reading file\n");
exit (1);
}
CloseFile (file_handle);
OpenFile opens FILE.DAT as an ASCII file for reading only. If OpenFile succeeds in opening the file, it returns a file handle with a positive integer value. ScanFile reads the ASCII representation of two integer values from the file. If ScanFile succeeds, it returns 2, indicating that two target specifiers were satisfied.
ASCII File with Comma-Separated Numbers to Real Array, with the Number of Elements at the Beginning of the File
double values[1000];
int file_handle, count;
file_handle = OpenFile ("FILE.DAT", 1, 2, 1);
ScanFile (file_handle, "%s>%i", &count);
if (count > 1000) {
FmtOut ("Count too large\n");
exit(1);
}
ScanFile (file_handle, "%s>%*f[x]", count, values);
CloseFile (file_handle);
The first ScanFile call reads the number of elements into the integer variable count. If the value in count exceeds the number of elements in the real array values, ScanFile reports an error. Otherwise, the second ScanFile call matches count to the asterisk (*) in the format string. ScanFile then reads the correct number of elements into values. The x modifier causes ScanFile to discard the comma separators.
Binary File to Integer Array, Assuming a Fixed Number of Elements
int readings[100];
int file_handle, nbytes;
file_handle = OpenFile ("FILE.DAT", 1, 2, 0);
ScanFile (file_handle, "%100i>%100i", readings);
nbytes = NumFmtdBytes ();
CloseFile (file_handle);
The ScanFile call reads 100 integers from a binary file and stores them in the integer array readings. If the ScanFile call is successful, nbytes = 400 (100 integers, 4 bytes per integer).
Binary File to Real Array, Assuming a Fixed Number of Elements
double waveform[100];
int file_handle, nbytes;
file_handle = OpenFile ("FILE.DAT", 1, 2, 0);
ScanFile (file_handle, "%100f>%100f", waveform);
nbytes = NumFmtdBytes ();
CloseFile (file_handle);
The ScanFile call reads 100 real numbers from a binary file and stores them in the real array waveform. If the ScanFile call is successful, nbytes = 800 (100 integers, 8 bytes per real number).
Binary File to Real Array, Assuming a Variable Number of Elements
void StoreArray (double x[], int count, char filename[])
{
int file_handle;
file_handle = OpenFile (filename, 1, 2, 0);
ScanFile (file_handle, "%*f>%*f", count, count, x);
CloseFile (file_handle);
}
This example shows how you can use a subroutine to read an array of real numbers from a binary file. The subroutine takes as parameters a real array, the number of elements to be read, and the filename.
The ScanFile call reads the first count elements of x from a binary file. ScanFile matches the two asterisks (*) in the format string to count. For instance, if count is 100, the format string is equivalent to %100f>100f.
Reading an Integer from the Standard Input
int n, num_readings;
n = 0;
while (n != 1) {
FmtOut ("Enter number of readings: ");
n = ScanIn ("%l>%i", &num_readings);
}
This example shows how to get user input from the keyboard. The FmtOut call writes the prompt string to the screen without a linefeed or carriage return. The ScanIn call attempts to read an integer value from the keyboard and place it in num_readings. If ScanIn succeeds, it returns 1, and FmtOut exits the loop. Otherwise, FmtOut repeats the prompt string.
The format string in the ScanIn call contains a source specifier of %l. This has two consequences. First, ScanIn returns whenever the user presses <Enter>, even if the input line is empty. This allows the prompt string to repeat at the beginning of each line until the user enters an integer value. Second, ScanIn discards any characters entered after the integer value.
Reading a String from the Standard Input
char filename[41];
int n;
n = 0;
while (n != 1) {
FmtOut ("Enter file name: ");
n = ScanIn ("%l>%s[w40q]", filename);
}
This example is similar to the previous example except that ScanIn reads a string, instead of an integer, from the keyboard. The w modifier prevents ScanIn from writing beyond the end of filename. Notice that the width specified is one less than the size of filename. This allows room for the ASCII NUL that ScanIn appends at the end of filename. The q modifier causes ScanIn to fill any unused bytes at the end of filename with ASCII NULs. Without the q modifier, all unused bytes are filled with spaces, except for the ASCII NUL at the end.
The call to ScanIn in this example skips over leading spaces and tabs and terminates the string on an embedded space. For other options, refer to the String to String example earlier in this section.
Reading a Line from the Standard Input
char buf[81];
nbytes = ReadLine (0, buf, 80);
The previous two examples show how to read single items from the keyboard. When you are prompted to enter several items on one line, it is often easier to read the entire line into a buffer before parsing it. You can do this using ReadLine.
The first parameter to ReadLine is a file handle. In this case, the file handle is zero, which is the handle reserved for the Standard Input. The other two parameters are a buffer and the maximum number of bytes to place in the buffer. ReadLine always appends an ASCII NUL at the end of the bytes read. Thus, the maximum number of bytes passed to ReadLine must be one less than the size of the buffer.
ReadLine transfers every character from the input line to the buffer, including leading spaces, embedded spaces, and trailing spaces, until ReadLine transfers the maximum number of bytes, in this case, 80. ReadLine discards any remaining characters at the end of the line. ReadLine never transfers the linefeed to the buffer.
ReadLine returns the number of bytes read, including the bytes discarded but excluding the linefeed.
In This Section
- String to Integer
- String to Short Integer
- String to Real
- String to Integer and Real
- String to String
- String to Integer and String
- String to Real, Skipping over Non-Numeric Characters in the String
- String to Real, After Finding a Semicolon in the String
- String to Real, After Finding a Substring in the String
- String with Comma-Separated ASCII Numbers to Real Array
- Scanning Strings That Are Not Null-Terminated
- Integer Array to Real Array
- Integer Array to Real Array with Byte Swapping
- Integer Array That Contains 1-Byte Integers to Real Array
- Strings That Contain Binary Integers to Integer Array
- Strings That Contain an IEEE-Format Real Number to a Real Variable
- ASCII File to Two Integers with Error Checking
- ASCII File with Comma-Separated Numbers to Real Array, with the Number of Elements at the Beginning of the File
- Binary File to Integer Array, Assuming a Fixed Number of Elements
- Binary File to Real Array, Assuming a Fixed Number of Elements
- Binary File to Real Array, Assuming a Variable Number of Elements
- Reading an Integer from the Standard Input
- Reading a String from the Standard Input
- Reading a Line from the Standard Input