Kapitel 7
Tegn

Kurt Nørmark
Institut for Datalogi, Aalborg Universitet


Sammendrag
Forrige lektion Næste lektion
Stikord Referencer Indhold
I denne lektion ser vi på datatypen char, herunder læsning fra tastaturet (og filer) samt skrivning af tegn på skærmen (filer). Endvidere ser vi på en antal eksempler på programmering med tegn.


Tegn og alfabet

Alfabet
Slide Indhold Stikord
Referencer 

Begrebet alfabet: Et alfabet er en ordnet mængde af bogstaver og andre tegn

  • ASCII alfabetet

    • American Standard Code for Information Interchange

    • Angiver tegnets placering i alfabetet ved at tildele tegnet en heltalsværdi - et code point

    • Det oprindelige ASCII tegnsæt indeholder 128 tegn

    • Det udvidede ASCII tegnsæt indeholder 256 tegn

      • De danske tegn 'æ', 'ø', 'å', 'Æ', 'Ø' og 'Å' er placeret i det udvidede ASCII tegnsæt

    • Appendix D i Problem Solving and Program Design

Siden starten af 90'erne er der arbejdet på Unicode alfabetet, som indeholder tegn fra mange forskellige kulturer.

Henvisninger

Datatypen char
Slide Indhold Stikord
Referencer 

Datatypen char repræsenterer mængden af mulige tegn i et standard alfabet

  • Datatypen char

    • Et tegn repræsenteres i én byte, som svarer til otte bits

    • Otte bit tegn giver netop mulighed for at repræsentere tegnene i det udvidede ASCII alfabet

    • Typen char er en heltalstype i C

Program: Et C program som udskriver en ASCII tegntabel.
#include <stdio.h>
#include <ctype.h>

int main(void) {
  int i;

  printf("\n");
  printf("%3s", "");           /* print top line above table */
  for (i = 0; i < 10; i++) 
    printf("%6d",i); 
  printf("\n");

  for (i = 0; i < 128; i++){   /* print the table */
    if (i % 10 == 0){          /* print leftmost column */
      printf("\n");
      printf("%3d", (i/10) * 10);    
    }
    if (isgraph(i))
      printf("%6c", i);
    else printf("%6s", "NP");
  }
  printf("\n\n");  

  return 0;
}

Program: Udskriften fra programmet.
        0     1     2     3     4     5     6     7     8     9

  0    NP    NP    NP    NP    NP    NP    NP    NP    NP    NP
 10    NP    NP    NP    NP    NP    NP    NP    NP    NP    NP
 20    NP    NP    NP    NP    NP    NP    NP    NP    NP    NP
 30    NP    NP    NP     !     "     #     $     %     &     '
 40     (     )     *     +     ,     -     .     /     0     1
 50     2     3     4     5     6     7     8     9     :     ;
 60     <     =     >     ?     @     A     B     C     D     E
 70     F     G     H     I     J     K     L     M     N     O
 80     P     Q     R     S     T     U     V     W     X     Y
 90     Z     [     \     ]     ^     _     `     a     b     c
100     d     e     f     g     h     i     j     k     l     m
110     n     o     p     q     r     s     t     u     v     w
120     x     y     z     {     |     }     ~    NP

Tegnkonstanter
Slide Indhold Stikord
Referencer 

Printbare værdier i typen char noteres ved at angive tegnet i enkelt quotes, eksempelvis 'a'.

Det er vigtigt at kunne skelne mellem tegn, strenge og tal.

Eksempelvis '7', "7" og 7.

  • Andre mulige notationer for tegn:

    • Escape notation af udvalgte tegn - nogle ikke-printbare

      • Eksempler:      '\n'      '\t'      '\''      '\\'

    • Oktal escape notation for tegn med code point 10, 97 og 110      (hhv '\n', 'a' og 'n')

      • Eksempler:      '\12'      '\141'      '\156'

    • Hexadecimal escape notation for de samme tegn      (samme tegn som de oktale)

      • Eksempler:      '\xa'      '\x61'      '\x6e'

Program: Tegnkonstanterne i et C program.
#include <stdio.h>

int main(void) {
  char ch[] = {'\n',  '\t',   '\'',   '\\', 
               '\12', '\141', '\156',
               '\xa', '\x61', '\x6e'
              };
  int i;

  for(i = 0; i <= sizeof(ch)/sizeof(char) - 1; i++)
    printf("ch[%d] = %c (as char) and %d (as integer)\n", i, ch[i], ch[i]);

  return 0;
}

Program: Output fra programmet.
ch[0] = 
 (as char) and 10 (as integer)
ch[1] = 	 (as char) and 9 (as integer)
ch[2] = ' (as char) and 39 (as integer)
ch[3] = \ (as char) and 92 (as integer)
ch[4] = 
 (as char) and 10 (as integer)
ch[5] = a (as char) and 97 (as integer)
ch[6] = n (as char) and 110 (as integer)
ch[7] = 
 (as char) and 10 (as integer)
ch[8] = a (as char) and 97 (as integer)
ch[9] = n (as char) and 110 (as integer)

Oktale og hexadecimal notation (1)
Slide Indhold Stikord
Referencer 

Hvad er oktal og hexadecimal tal notation?

Hvorfor er oktal og hexadecimal notation praktisk i forhold til normal decimal notation?

Det decimale tal 14 vises binært, oktalt og hexadecimalt

Figur. En illustration af binære, oktale og hexadecimale tal.

Oktal og hexadecimal tal notation tillader en ciffervis konvertering til binær notation

Oktale og hexedecimal notation (2)
Slide Indhold Stikord
Referencer 

Eksempler på binære, oktale og hexadecimale talopløsninger

  • Binære tal: Grundtal 2

    • Eksempel:      14 = 1 · 23 + 1 · 22 + 1 · 21 + 0 · 20

  • Oktale tal: Grundtal 8

    • Eksempel:      14 = 1 · 81 + 6 · 80

  • Hexadecimale tal: Grundtal 16

    • Eksempel:      14 = 14 · 160 = e · 160

  • Decimale tal: Grundtal 10

    • Eksempel:      14 = 1 · 101 + 4 · 100

Senere i denne lektion vil vi programmere funktioner der kan konvertere mellem talsystemerne

Tegn aritmetik
Slide Indhold Stikord
Referencer 

Det er muligt at udføre aritmetiske operationer på tegn - forstået som aritmetik på de underliggende ASCII værdier

  • Addition af et tal til et tegn

    • '0' + 7 == '7'

    • Tegnet 7 positioner længere fremme i tegntabellen

  • Subtraktion af et tal fra et tegn

    • 'k' - 1 == 'j'

    • Tegnet før k

  • Subtraktion af to tegn

    • 'a' - 'A'

    • Afstanden mellem små og store bogstaver i tegntabellen

  • Sammenligning af to tegn

    • 'a' < 'b'

    • Tegnet a kommer før b. Vurdering af alfabetisk rækkefølge

Klassificering af tegn
Slide Indhold Stikord
Referencer 

Biblioteket ctype.h understøtter en række abstraktioner, som klassificerer tegn

  • Tegn

    • Kontrol tegn     -     iscntrl(c)

    • Printbare tegn     -     isprint(c)

      • Blanke tegn     -     isspace(c)

      • Grafiske tegn     -     isgraph(c)

        • Punkt tegn     -     ispunct(c)

        • Alfanumeriske tegn     -     isalnum(c)

          • Alfabetiske tegn     -     isalpha(c)

            • Små bogstaver     -     islower(c)

            • Store bogstaver     -     isupper(c)

          • Numeriske tegn     -     isdigit(c)

Input og output af tegn: getchar og putchar
Slide Indhold Stikord
Referencer 

Abstraktionerne getchar og putchar giver mulighed for input og output af enkelttegn

Læsning af ét tegn fra standard input - skrivning af ét tegn på standard output

getchar og putchar er lavniveau alternativer til scanf og printf

Program: En funktion der læser et heltal som enkelttegn - basal udgave.
int read_int(){          // int-read-0-better.c
  int res = 0;  char c;

  c = getchar();
  while (isdigit(c)) {
    res = res * 10 + (c - '0');
    c = getchar();
  }

  return res;
}  

Program: En mere koncentreret version af read_int.
int read_int(){
  int res = 0;  char c;

  while (isdigit(c = getchar()))
    res = res * 10 + (c - '0');

  return res;
}  

Program: Funktionen read_int og en main funktion som kalder read_int 5 gange.
#include <stdio.h>

int read_int();

int main(void) {
  int i, n = 0;

  for (i = 1; i <= 5; i++){
    printf("Enter an integer: ");
    n = read_int();
    printf("Decimal value: %d\n", n);
  }

  return 0;
}

int read_int(){
  int res = 0;  char c;

  while (isdigit(c = getchar()))
    res = res * 10 + (c - '0');

  return res;
}  

Program: En mere brugbar udgave med mulighed for fortegn og bedre linieafslutning.
#include <stdio.h>
#include <stdlib.h>

int read_int();

int main(void) {
  int i, n = 0;

  for (i = 1; i <= 5; i++){
    printf("Enter an integer: ");
    n = read_int();
    printf("Decimal value: %d\n", n);
  }

  return 0;
}

int read_int(){
  int res = 0;  char c; int sign = 1;

  /* Handle initial sign, if any */
  c = getchar();
  if      (c == '+')   {sign =  1; c = getchar();}
  else if (c == '-')   {sign = -1; c = getchar();}
  else if (isdigit(c)) {sign =  1;}
  else                 {printf("Int read error"); 
                        exit(EXIT_FAILURE);}

  /* Read digits - first char is ready in c*/
  while (isdigit(c)){
    res = res * 10 + (c - '0');
    c = getchar();
  }

  /* Read the rest of the line */
  while (c != '\n') c = getchar();

  return sign * res;
}  

Eksempler: Konvertering mellem talsystemer
Slide Indhold Stikord
Referencer 

Vi vil nu se på et program, der indlæser et tal i et n talsystem, og som konverterer det til et decimalt tal.

Vi vil tilsvarende se på et program, der konverterer et decimalt tal til et tal i et andet talsystem.

Programmerne illustrerer tillige getchar og putchar.

Program: Et C program der omregner et tal fra et talsystem til titalsystemet og udskriver resultatet.
#include <stdio.h>
#include <stdlib.h>

int read_in_base(int);
void skip_rest_of_input_line (void);

int main(void) {
  int i, n, base;

  printf("THIS PROGRAM CONVERTS NUMBERS IN A " 
         "GIVEN BASE (FROM 2 TO 36) TO A DECIMAL NUMBER.\n\n");
  do {
    printf("Enter number base (0 terminates the program, max 36): ");
    scanf("%d", &base); skip_rest_of_input_line();
    if (base > 0){
      printf("Enter a non-negative number to be converted " 
             "to decimal notation: ");
      n = read_in_base(base);
      if (n >= 0)
        printf("The decimal number is: %d\n", n);
      else {
        printf("You have typed an illegal ciffer - TRY AGAIN\n"); 
        skip_rest_of_input_line();
      }
    }
  } while (base > 0);
  
  return 0;
}

int calculate_ciffer_number(char ciffer){
  int ciffer_number;

  if (ciffer >= '0' && ciffer <= '9')
    ciffer_number = ciffer - '0';
  else if (ciffer >= 'a' && ciffer <= 'z')
    ciffer_number = ciffer - 'a' + 10;
  else {
    printf("Should not happen. Bye\n");
    exit(EXIT_FAILURE);
  }
  return ciffer_number;
}

/* Read a number in base and return the corresponding decimal number.
   Return -1 if erroneous input is encountered. */
int read_in_base(int base){
  int ciffer_number, res = 0, done = 0;
  char ciffer;

  do {
    ciffer = getchar();

    if ((ciffer >= '0' && ciffer <= '9') ||  (ciffer >= 'a' && ciffer <= 'z'))
      ciffer_number = calculate_ciffer_number(ciffer);
    else if (ciffer == '\n')
      done = 1; 
    else return -1;

    if (ciffer_number >= 0 && ciffer_number < base){
      if (!done) res = res * base + ciffer_number;
    }
    else return -1;
  }
  while (!done);

  return res;
}     

void skip_rest_of_input_line (void){
  char c;

  c = getchar();
  while (c != '\n') c = getchar();
}

Program: Et C program der omregner et tal fra titalsystemet til et andet talsystem og udskriver resultatet.
#include <stdio.h>
#define MAX_BASE_SUPPORTED 36

void print_in_base(int, int);

int main(void) {
  int i, n, base;

  printf("THIS PROGRAM CONVERTS DECIMAL NUMBERS " 
         "TO NUMBERS IN ANOTHER BASE (FROM 2 TO 36).\n\n");

  for (i = 1; i <= 5; i++){
    printf("Enter positive decimal number "
           "and number base (at least two): ");
    scanf(" %d %d", &n, &base);

    if ((n > 0) && (base >= 2) && (base <= MAX_BASE_SUPPORTED)){
      print_in_base(n, base); 
      printf("\n");
    }
    else
      printf("Illegal input. Try again\n");
  }
  
  return 0;
}

/* Convert the decimal number n to base and print the result */
void print_in_base(int n, int base){
  int ciffer;

  if (n > 0){
    ciffer = n % base;   /* find least significant ciffer */

    /* RECURSIVELY, find and print most significant ciffers */
    print_in_base(n / base, base);  

    /* print least significant ciffer */    
    if (ciffer >= 0 && ciffer <= 9)
      putchar('0' + ciffer);
    else if (ciffer >= 10 && ciffer <= MAX_BASE_SUPPORTED)
      putchar('a' + ciffer - 10);
    else putchar('?');
  } 
}  

Eksempel: Kopiering af fil
Slide Indhold Stikord
Referencer 

Det er meget simpelt at skrive et program som kopierer en fil til en anden fil

Med brug af input redirection og output redirection

Program: Et C program der kopierer input til output.
#include <stdio.h>

int main(void) {
  int c;

  while ((c = getchar()) != EOF)
    putchar(c);
  
  return 0;
}

Program: En version uden brug af udtryk med side-effekt.
#include <stdio.h>

int main(void) {

  int c;

  c = getchar();
  while (c != EOF){
    putchar(c);
    c = getchar();
  }
  
  return 0;
}

Program: Oversættelse og udførelse af copy.c med input og output redirection.
normark$ gcc -o copy-file copy.c
normark$ ./copy-file < copy.c > copy-of-copy.c


Samlede referencer
Indhold Stikord
A tutorial on character code issues
Unicode tegntabeller

 

Kapitel 7: Tegn
Kursets hjemmeside     Forfatteren's hjemmeside     Om frembringelsen af disse sider     Forrige lektion (top)     Næste lektion (top)     Forrige lektion (bund)     Næste lektion (bund)     
Genereret: 19. oktober 2012, 10:50:20