Kapitel 10
Tegn og Tekststrenge

Kurt Nørmark
Institut for Datalogi, Aalborg Universitet


Sammendrag
Forrige lektion Næste lektion
Stikord Referencer Indhold
I denne lektion studerer vi forskellige aspekter af tekststrenge.


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 i C
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: Udskriften fra programmet herunder.
        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

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;
}

Tegnkonstanter
Slide Indhold Stikord
Referencer 

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

Ikke-printbare værdier noteres ved brug af escape notation med brug af back slash tegnet

  • Escape notation:

    • 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)

Det er vigtigt at kunne skelne mellem tegn, strenge og tal, eksempelvis '7', "7" og 7.

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

Hexadecimal tal notation gør det muligt at notere én byte med to hexadecimale cifre

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


Strenge og tekststrenge

Strenge og tekststrenge
Slide Indhold Stikord
Referencer 

Begrebet streng: En streng er en sekvens af data af samme type
Begrebet tekststreng: En tekststreng er en streng af datatypen tegn

  • Almen notation for tekststrenge:

    • "En tekststreng"

  • Den tomme streng

    • Strengen der ikke indeholder data

    • Strengen af længde 0 - den kortest mulige streng

    • Den tomme tekststreng noteres naturligt som ""

Tekststrenge spiller en vigtig rolle i de fleste programmer vi skriver


Tekststrenge i C

Tekststrenge og arrays
Slide Indhold Stikord
Referencer 

En tekststreng i C er et nulafsluttet array med elementtypen char.

En tekststreng i C er dermed af typen char *

Figur. En illustration af en nulafsluttet tekststreng i C

  • Det afsluttende nultegn kaldes en sentinel

    • Oversættes direkte som en 'vagt'

    • Eksplicit markering af afslutningen af tekststrengen

Figur. En tekststreng som er placeret 'i midten' af et array of char

En tekststreng i C skal ikke nødvendigvis udfylde hele det omkringliggende array

Initialisering og assignment af tekststrenge
Slide Indhold Stikord
Referencer 

En tekststreng kan initialiseres på flere forskellige måder

Program: Forskellige initialiseringer af tekststrenge.
  char str_1[] = {'A', 'a', 'l', 'b', 'o', 'r', 'g', '\0'};

  char str_2[] = "Aalborg";

  char *str_3 = "Aalborg";

  char str_4[8];
  str_4[0] = 'A';  str_4[1] = 'a';  str_4[2] = 'l';  
  str_4[3] = 'b';  str_4[4] = 'o';  str_4[5] = 'r';  
  str_4[6] = 'g';  str_4[7] = '\0';   

Program: De fire streng initialiseringer i et helt C program - herunder udskrivninger af de fire tekststrenge.
#include <stdio.h>

int main(void) {

  char str_1[] = {'A', 'a', 'l', 'b', 'o', 'r', 'g', '\0'};

  char str_2[] = "Aalborg";

  char *str_3 = "Aalborg";

  char str_4[8];
  str_4[0] = 'A';  str_4[1] = 'a';  str_4[2] = 'l';  
  str_4[3] = 'b';  str_4[4] = 'o';  str_4[5] = 'r';  
  str_4[6] = 'g';  str_4[7] = '\0';     

  printf("%s\n%s\n%s\n%s\n", str_1, str_2, str_3, str_4);
  
  return 0;
}

Program: Output fra programmet.
Aalborg
Aalborg
Aalborg
Aalborg

Program: Tilsvarende forsøg på assignments til de fire tekststrenge.
#include <stdio.h>
#include <string.h>

int main(void) {

  char str_1[8], str_2[8], *str_3, str_4[8];

  /* Ulovlig brug af initializer */
  str_1 = {'A', 'a', 'l', 'b', 'o', 'r', 'g', '\0'};


  /* Illegal assignment to array. The array name is constant */
  /* Implicite copying of characters do not take place in C. */
  str_2 = "Aalborg";

  /* Alternative: copy the characters yourself */
  strcpy(str_2, "Aalborg");


  /* Pointer assignment - OK */
  str_3 = "Aalborg";

  /* Char by char Assignment - OK, but tedious */
  str_4[0] = 'A';  str_4[1] = 'a';  str_4[2] = 'l';  
  str_4[3] = 'b';  str_4[4] = 'o';  str_4[5] = 'r';  
  str_4[6] = 'g';  str_4[7] = '\0';     

  printf("%s\n%s\n%s\n%s\n", str_1, str_2, str_3, str_4);
  
  return 0;
}

Ved initialisering via tekstkonstanter tilføjes nultegnet automatisk af compileren

Tekststrenge og pointere
Slide Indhold Stikord
Referencer 

En tekststreng opfattes i C som en pointer til det første tegn i et char array

Dette følger direkte af den generelle sammenhæng mellem arrays og pointere

Illustration af programmernes arrays findes på næste slide

Program: Et program der ved brug af pointere kopierer strengen "Aalborg" ind midt i en anden streng.
#include <stdio.h>

int main(void) {
  char str_aal[] = "Aalborg";
  char str[14];

  char *str_1, *str_2;
  int i;

  /* fill str with '-' */
  for(i = 0; i < 14; i++)
    str[i] = '-';

  /* let str_1 and str_2 be pointers to target and source resp. */
  str_1 = str + 2;  str_2 = str_aal;

  /* copy str_all into the middle of str */
  while(*str_2 != '\0'){
    *str_1 = *str_2;
    str_1++, str_2++;
  }

  /* terminate str */
  *str_1 = '\0';

  printf("%s\n", str);  
  
  return 0;
}

Program: Et tilsvarende program, kortere og mere kryptisk - for 'rigtige C programmører'.
#include <stdio.h>

int main(void) {
  char str_aal[] = "Aalborg";
  char str[14];

  char *str_1, *str_2;
  int i;

  /* fill str with '-' */
  for(i = 0; i < 14; i++)
    str[i] = '-';

  /* let str_1 and str_2 be pointers to target and source resp. */
  str_1 = str + 2; str_2 = str_aal;

  /* copy str_all into the middle of str */
  while(*str_1++ = *str_2++);

  printf("%s\n", str);  
  
  return 0;
}

Program: Output fra programmet.
--Aalborg

Program: Samme program med brug af strcpy.
#include <stdio.h>
#include <string.h>

int main(void) {
  char str_aal[] = "Aalborg";
  char str[14];
  int i;

  /* fill str with '-' */
  for(i = 0; i < 14; i++)
    str[i] = '-';

  strcpy(str + 2, str_aal);

  printf("%s\n", str);  
  
  return 0;
}

Program: Output fra programmet.
--Aalborg

I praksis anvendes strcpy eller strncpy fra string.h til kopiering af strenge

Kopiering af tekststreng - med håndkraft
Slide Indhold Stikord
Referencer 

En illustration af kopieringen foretaget i programmerne på forrige slide

Figur. En illustration af kopiering af en tekststreng - ved håndkraft med for-løkke.

Ændringer af tekststrenge
Slide Indhold Stikord
Referencer 

Tekststrenge, til hvilke der er allokeret plads i et array, kan ændres (muteres)

Tekststrenge, der i kildeprogrammet er angivet som en streng konstant og refereret af en pointer, kan ikke ændres

Program: Et program der ændrer det andet tegn i Aalborg fra 'a' til 'A'.
  char str_1[] = {'A', 'a', 'l', 'b', 'o', 'r', 'g', '\0'};
  *(str_1 + 1) = 'A';     // OK

  char str_2[] = "Aalborg";
  *(str_2 + 1) = 'A';     // OK

  char *str_3 = "Aalborg";
  *(str_3 + 1) = 'A';     // Potentiel fejl. 
                          // Kan give segmentation fault under kørsel.

  char str_4[8];          // OK
  str_4[0] = 'A';  str_4[1] = 'a';  str_4[2] = 'l';  
  str_4[3] = 'b';  str_4[4] = 'o';  str_4[5] = 'r';  
  str_4[6] = 'g';  str_4[7] = '\0';     
  *(str_4 + 1) = 'A';

Program: Hele programmet der ændrer det andet tegn i Aalborg fra 'a' til 'A'.
#include <stdio.h>

int main(void) {

  char str_1[] = {'A', 'a', 'l', 'b', 'o', 'r', 'g', '\0'};
  *(str_1 + 1) = 'A';     // OK

  char str_2[] = "Aalborg";
  *(str_2 + 1) = 'A';     // OK

  char *str_3 = "Aalborg";
  *(str_3 + 1) = 'A';     // Potentiel fejl. 
                          // Kan give segmentation fault under kørsel.

  char str_4[8];          // OK
  str_4[0] = 'A';  str_4[1] = 'a';  str_4[2] = 'l';  
  str_4[3] = 'b';  str_4[4] = 'o';  str_4[5] = 'r';  
  str_4[6] = 'g';  str_4[7] = '\0';     
  *(str_4 + 1) = 'A';

  printf("%s\n%s\n%s\n%s\n", str_1, str_2, str_3, str_4);
  
  return 0;
}

Opgave 10.2. Funktionen strrev

Strengomvending består i at bytte om på tegnene i en tekststreng, således at de første tegn ender med at være de sidste. Eksempelvis er strengomvendingen af "streng" lig med "gnerts".

Programmer funktionen strrev(char *str), som omvender tegnene i parameteren str. Bemærk at parameteren str både tjener som input og output parameter. Vi ønsker altså at bytte om på tegnene i det char array, som str peger på.

Tekststrenge i forhold til tegn
Slide Indhold Stikord
Referencer 

De to værdier 'a' og "a" er forskellige

  • 'a'

    • Et enkelt tegn af typen char

    • Heltallet 97

  • "a"

    • Et array med to elementer

    • Element nummer nul er tegnet 'a' og element nummer et er tegnet '\0'

Den tomme streng og NULL
Slide Indhold Stikord
Referencer 

Man skal kunne skelne mellem den tomme tesktstreng og en NULL pointer

NULL og "" er forskellige

  • NULL

    • NULL er en pointer værdi

    • NULL værdien bruges for en pointer, der ikke peger på en plads i lageret

    • Heltallet 0

  • Den tomme streng ""

    • Den tomme string "" er en streng værdi

    • "" er et array med ét element, nemlig '\0' tegnet

Lange tekststrenge i C Programmer
Slide Indhold Stikord
Referencer 

Lange tekststrenge i et C program kan deles over flere linier

Nabo tekststrenge som optræder direkte i et C program konkateneres implicit

Program: Et C program med en lang tekststreng i programmet - et problematisk kildeprogram.
#include <stdio.h>
#include <string.h>

int main(void) {
  char long_string_1[] = 
    "This is a long string that will cause layout problem in our program. It would be much nicer if we somehow are able to break this string into smaller pieces. This can be done in several different ways in C.";

  printf("%s: OF LENGTH: %d\n", long_string_1, strlen(long_string_1));
  return 0;
}

Program: Lange tekststrenge med backslashes - Backslash og EOL tegn ignoeres.
#include <stdio.h>
#include <string.h>

int main(void) {
  char long_string_1[] = 
   "This is a long string that will cause layout problem in our program. \
It would be much nicer if we somehow are able to break this string into smaller pieces. \
This can be done in several different ways in C.";

  printf("%s: OF LENGTH: %d\n", long_string_1, strlen(long_string_1));
  return 0;
}

Program: Implicit konkatenering af nabo tekststreng konstanter.
#include <stdio.h>
#include <string.h>

int main(void) {
  char long_string_1[] = 
    "This is a long string that will cause layout problem in our program. "
    "It would be much nicer if we somehow are able to break this string into smaller pieces. "
    "This can be done in several different ways in C.";

  printf("%s: OF LENGTH: %d\n", long_string_1, strlen(long_string_1));
  return 0;
}

Program: Program output - det samme for alle tre programmer.
This is a long string that will cause layout problem in our program. It would be much nicer if we somehow are able to break this string into smaller pieces. This can be done in several different ways in C.: OF LENGTH: 205

Ovenstående tre programmer er identiske: de giver samme output

Program: Implicit konkatenering virker kun på strengkonstanter i kildeprogrammet - Dette program compilerer ikke.
#include <stdio.h>
#include <string.h>

int main(void) {
  char str_1[] = "String one",
       str_2[] = "String two";

  printf("%s: OF LENGTH: %d\n", str_1 str_2, strlen(str_1) + strlen(str_2));
  return 0;
}

Program: Implicit konkatenering af formateringsstrengen i printf.
#include <stdio.h>
#include <string.h>

int main(void) {
  printf("We have a long text that must be printed.\n"
         "The text contains placeholders such as %d and %c. "
         "This ends the string.\n",
         123, 'a');
  return 0;
}

Program: Output fra ovenstående program.
We have a long text that must be printed.
The text contains placeholders such as 123 and a. This ends the string.


Leksikografisk ordning

Leksikografisk ordning af strenge
Slide Indhold Stikord
Referencer 

Ordningen af tegn giver anledning til en ordning af tegnstrenge (tekststrenge)

Den normale alfabetiske ordning af tekststrenge spiller en vigtig rolle ved opslag i leksika, telefonbøger, mv.

Vi vil her definere hvad det betyder af strengen s er mindre end strengen t

  • Lad e betegne den tomme streng "" og lad s og t være to tekststrenge

  • s < t      hvis og kun hvis der findes tegn c og d samt to kortere strenge u og v

    • s = e
      t = c u           eller

    • s = c u
      t = d v

      • c < d

      • c = d og u < v

Notationen ovenfor er ikke C notation

Leksikografisk ordning af strenge
Slide Indhold Stikord
Referencer 

Her diskuterer vi leksikografisk ordning på en mere praktisk måde

Program: Konkrete eksempler på leksikografisk ordning - ikke C syntaks.
The following logical expressions are all true - not C expressions:

  "" < "abc"

  "abc" < "abcd"

  "abc" < "bde"

  "abc" < "acd"

Program: Konkrete eksempler på leksikografisk ordning - med strcmp og i C syntaks.
The following logical expressions are C expressions - and they are all true:

  strcmp("", "abc")) == -1
 
  strcmp("abc", "abcd")) == -1

  strcmp("abc", "bde")) == -1

  strcmp("abc", "acd")) == -1

Program: Konkrete eksempler på leksikografisk ordning - med strcmp.
#include <stdio.h>
#include <string.h>

int main(void) {
  printf("%d\n",  strcmp("", "abc"));      // -1
  printf("%d\n",  strcmp("abc", "abcd"));  // -1
  printf("%d\n",  strcmp("abc", "bde"));   // -1
  printf("%d\n",  strcmp("abc", "acd"));   // -1
  
  return 0;
}

Lighed af strenge (1)
Slide Indhold Stikord
Referencer 

Der er to mulige fortolkninger af lighed af to strenge s og t

Figur. En illustration af reference lighed og strukturel lighed mellem char * variable

Lighed af strenge (2)
Slide Indhold Stikord
Referencer 

  • Pointerværdierne indeholdt i de to variable s og t er ens

    • s og t peger på det samme array af tegn

    • Hvis vi ændrer på tegnene i s ændres tegnene i t automatisk

    • Reference lighed

  • s og t udpeger forskellige arrays, med tegn der parvis er ens

    • Hvis vi ændrer på tegnene i s ændres intet i t

    • Strukturel lighed

Hvis to strenge er reference ens er de også strukturelt ens, men ikke nødvendigvis omvendt

Funktionen strcmp fra string.h
Slide Indhold Stikord
Referencer 

Functionen strcmp fra string.h implementerer den leksikografiske ordning samt strukturel lighed på tekststrenge i C

  • Tre mulige output af strcmp(str1,str2):

    • Positivt heltal:

      • str1 er leksikografisk større end str2

    • Nul:

      • str1 og str2 er strukturelt ens

    • Negativt heltal:

      • str1 er leksikografisk mindre end str2

Henvisning

Program: Et program der illustrerer den leksikografiske ordning af tekststrenge i C.
#include <stdio.h>
#include <string.h>

void pr(char*, char*, int);

int main(void) {

  int b1 = strcmp("book", "shelf");    
  int b2 = strcmp("shelf", "book");    
  int b3 = strcmp("","book");
  int b4 = strcmp("book","bookshelf"); 
  int b5 = strcmp("book", "book");
  int b6 = strcmp("7book", "book");
  int b7 = strcmp("BOOK", "book");

  pr("book", "shelf", b1);
  pr("shelf", "book", b2);
  pr("", "book", b3);
  pr("book", "bookshelf", b4);
  pr("book", "book", b5);
  pr("7book","book", b6);
  pr("BOOK", "book", b7);
  
  return 0;
}

void pr(char *s, char *t, int r){
 printf("strcmp(\"%s\",\"%s\") = %i\n", s,t,r);
}

Program: Mulig output fra programmet.
strcmp("book","shelf") = -17
strcmp("shelf","book") = 17
strcmp("","book") = -98
strcmp("book","bookshelf") = -115
strcmp("book","book") = 0
strcmp("7book","book") = -43
strcmp("BOOK","book") = -32

Program: Mulig output fra programmet.
strcmp("book","shelf") = -1
strcmp("shelf","book") = 1
strcmp("","book") = -1
strcmp("book","bookshelf") = -1
strcmp("book","book") = 0
strcmp("7book","book") = -1
strcmp("BOOK","book") = -1

Opgave 10.3. Din egen udgave af funktionen strcmp

Funktionen strcmp fra string.h sammenligner to tekststrenge med hinanden, som beskrevet på denne slide.

Programmer din egen rekursive udgave af strcmp. En rekursiv strcmp funktion programmeres uden brug af while eller for-løkker.

Lad dig evt. inspirere at vores definition på leksikografisk ordning, som på rekursiv vis definerer en 'mindre end' operator på tekststrenge.


Tidligere eksempler

Konvertering mellem talsystemer
Slide Indhold Stikord
Referencer 

I en tidligere lektion har vi programmeret funktioner der konverterer tal mellem forskellige talsystemer

De involverede funktioner læste/skrev input/output med getchar og putchar

Det er mere alsidigt at skrive funktioner, der modtager eller returnerer tekststrenge

Henvisning

Program: En funktion der konverterer et tal n i base talsystemet (en streng) til et decimalt tal.
/* Convert the string n to a decimal number in base and return it.
   Assume that input string is without errors */
int to_decimal_number(char *n, int base){
  int ciffer_number, res = 0;
  char *ciffer_ptr = &n[0], ciffer = *ciffer_ptr;

  do {
    if (ciffer >= '0' && ciffer <= '9')
      ciffer_number = ciffer - '0';
    else if (ciffer >= 'a' && ciffer <= 'z')
      ciffer_number = ciffer - 'a' + 10;
    else ciffer_number = -1;   /* error */

    if (ciffer_number >= 0 && ciffer_number < base)
      res = res * base + ciffer_number;

    ciffer_ptr++; ciffer = *ciffer_ptr;
  }
  while (ciffer != '\0');

  return res;
}   

Program: Hele programmet.
#include <stdio.h>
#include <stdlib.h>

int read_in_base(int);

int main(void) {
  int i, n, base;
  char *the_number[20];

  for (i = 1; i <= 5; i++){
    printf("Enter number base (a decimal number)"
           "and a number in that base: ");
    scanf("%d %s", &base, the_number); 
    printf("The decimal number is: %d\n",
            to_decimal_number(the_number, base));
  }
  
  return 0;
}

/* Convert the string n to a decimal number in base and return it.
   Assume that input string is without errors */
int to_decimal_number(char *n, int base){
  int ciffer_number, res = 0;
  char *ciffer_ptr = &n[0], ciffer = *ciffer_ptr;

  do {
    if (ciffer >= '0' && ciffer <= '9')
      ciffer_number = ciffer - '0';
    else if (ciffer >= 'a' && ciffer <= 'z')
      ciffer_number = ciffer - 'a' + 10;
    else ciffer_number = -1;   /* error */

    if (ciffer_number >= 0 && ciffer_number < base)
      res = res * base + ciffer_number;

    ciffer_ptr++; ciffer = *ciffer_ptr;
  }
  while (ciffer != '\0');

  return res;
}   

Udskrivning af enumeration konstanter
Slide Indhold Stikord
Referencer 

I en tidligere lektion har vi programmeret funktioner der udskriver navnene på enumeration konstanter

De involverede funktioner skrev output med printf

Det er mere alsidigt at skrive funktioner der returnerer tekststrenge

Henvisning

Program: En funktion som returnerer en symbolsk ugedag (en streng) givet dagens nummer.
/* Return the symbolic name of day d */
char *print_name_of_day(days  d){
  char *result;
  switch (d) {
    case sunday: result = "Sunday";
       break;
    case monday: result = "Monday";
       break;
    case tuesday: result = "Tuesday";
       break;
    case wednesday: result = "Wednesday";
       break;
    case thursday: result = "Thursday";
       break;
    case friday: result = "Friday";
       break;
    case saturday: result = "Saturday";
       break;
  }
  return result;
}  

Program: Hele programmet.
#include <stdio.h>

enum days {sunday, monday, tuesday, wednesday, thursday, 
           friday, saturday};
typedef enum days days;

days  next_day_of(days  d){
  return ( days ) (((int) d + 1) % 7);
}  

/* Return the symbolic name of day d */
char *print_name_of_day(days  d){
  char *result;
  switch (d) {
    case sunday: result = "Sunday";
       break;
    case monday: result = "Monday";
       break;
    case tuesday: result = "Tuesday";
       break;
    case wednesday: result = "Wednesday";
       break;
    case thursday: result = "Thursday";
       break;
    case friday: result = "Friday";
       break;
    case saturday: result = "Saturday";
       break;
  }
  return result;
}     

int main(void){
  
  days  day1 = saturday,  another_day;
  int i;

  printf("Day1 is %d\n", day1);

  printf("Day1 is also %s\n", print_name_of_day(day1));

  another_day = day1;
  for(i = 1; i <= 3; i++)
    another_day = next_day_of(another_day);
  
  printf("Three days after day1: %s", 
          print_name_of_day(another_day));
  printf("\n");

  return 0;
}    

Program: Hele programmet - programmeret med et array af ugedagnes navne.
#include <stdio.h>

enum days {sunday, monday, tuesday, wednesday, thursday, 
           friday, saturday};
typedef enum days days;

char *day_names[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", 
                      "Friday", "Saturday"};

days  next_day_of(days  d){
  return ( days ) (((int) d + 1) % 7);
}  

/* Return the symbolic name of day d */
char *print_name_of_day(days  d){
  return day_names[(int)d];
}     

int main(void){
  
  days  day1 = saturday,  another_day;
  int i;

  printf("Day1 is %d\n", day1);

  printf("Day1 is also %s\n", print_name_of_day(day1));

  another_day = day1;
  for(i = 1; i <= 3; i++)
    another_day = next_day_of(another_day);
  
  printf("Three days after day1: %s", 
          print_name_of_day(another_day));
  printf("\n");

  return 0;
}    

Program: Program output - ens i de to programmer.
Day1 is 6
Day1 is also Saturday
Three days after day1: Tuesday


Biblioteket string.h

Oversigt
Slide Indhold Stikord
Referencer 

  • char *strcat(char *s1, const char *s2);

    • Sammensætter s1 og s2 i bagenden af s1. Nultegnet i s1 overskrives.

    • Nyt nultegn indsættes efter kopi af s2. Kræver plads nok i s1. Returnerer s1.

  • char *strcpy(char *s1, const char *s2);

    • Kopierer s2 ind i starten af s1, inklusive 0 tegnet.

    • Kræver plads nok i s1. Returnerer s1.

  • char *strncpy(char *s1, const char *s2, size_t n);

    • Kopierer n tegn (eller indtil nultegn) fra s2 ind i starten af s1. Nultegnet fra s2 kopieres ikke.

    • Fylder om nødvendigt op med nultegn, så der ialt kopieres netop n tegn.

  • char *strchr(const char *s, int c);

    • Returnerer pointer til første forekomst af c i s. Ellers NULL.

    • Variant: strrchr - søger bagfra.

  • char *strstr(const char *s1, const char *s2);

    • Returnerer en pointer til den første forekomst af s2 i s1. Ellers NULL.

  • size_t strlen(const char *s);

    • Returnerer antallet af tegn i s - nultegnet tæller ikke med.

  • int strcmp(const char *s1, const char *s2);

    • Leksikografisk sammenligning af s1 og s2. Negativ, nul, eller positiv returværdi.

    • Variant: strncmp - sammenligner kun n tegn.

Ligesom de andre standardbibliotekter er string.h beskrevet i appendix B af Problem Solving and Program Design in C

Sammensætning af tekststrenge - illustration
Slide Indhold Stikord
Referencer 

Figur. En illustration af strcat

Henvisning

Sammensætning af tekststrenge
Slide Indhold Stikord
Referencer 

char *strcat(char *s1, const char *s2)

Funktionen strcat indsætter strengen s2 i bagenden af en anden streng s1 forudsat der er plads efter nultegnet

Program: Et program der illustrerer strcat og strlen.
#include <stdio.h>
#include <string.h>

int main(void) {

  char s1[14] = "Aalborg";  
  char s2[14] = " Uni";
  char *res;

  res = strcat(s1,s2);
  printf("%s: %i chars\n", res, strlen(s1));
  
  return 0;
}

Program: Output fra programmet.
Aalborg Uni: 11 chars

Kopiering af tekststrenge - illustration
Slide Indhold Stikord
Referencer 

Figur. En illustration af strncpy

Henvisning

Kopiering af tekststrenge - illustration
Slide Indhold Stikord
Referencer 

Figur. En illustration af strncpy

Henvisning

Kopiering af tekststrenge
Slide Indhold Stikord
Referencer 

char *strcpy(char *s1, const char *s2)

Funktionen strcpy kopierer en tekststreng s2 ind i et char array s1, til og med det afsluttende 0-tegn

strcpy antager at der er plads nok i arrayet - hvis ikke overskrives nabo celler i lageret

Program: Et program der illustrerer strcat og strlen.
#include <stdio.h>
#include <string.h>

void case1(void){
  char s1[14] = "Aalborg";
  char s2[14] = " Uni";
  
  strcpy(s1, s2);
  printf("%s: %i chars\n", s1, strlen(s1));   
}

void case2(void){
  char s1[4];
  char s2[14] = " University";
  
  strcpy(s1, s2);                  /* Insufficient space in s1. Very problematic */
  printf("%s: %i chars\n", s1, strlen(s1));  
}

int main(void) {
  case1();
  case2();
  return 0;
}

Program: Output fra programmet.
 Uni: 4 chars
 University: 11 chars

En alternativ funktion til strcpy
Slide Indhold Stikord
Referencer 

Som de fleste andre funktioner i string.h allokerers der ikke lager i strcpy

Her vil vi programmere en streng-kopierings funktion der allokerer plads til en ny kopi

Program: Et funktioner der allokerer plads til og kopierer en streng.
/* Copy s to a fresh allocated string and return it */
char *string_copy(const char *s){
  char *new_str;

  new_str = (char *)malloc(strlen(s)+1);
  if (new_str == NULL){
    printf("Cannot copy string.\n");
    exit(EXIT_FAILURE);
  }
  strcpy(new_str,s);

  return new_str;
}  

Program: Hele programmet.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/* Copy s to a fresh allocated string and return it */
char *string_copy(const char *s){
  char *new_str;

  new_str = (char *)malloc(strlen(s)+1);
  if (new_str == NULL){
    printf("Cannot copy string.\n");
    exit(EXIT_FAILURE);
  }
  strcpy(new_str,s);

  return new_str;
}  


int main(void) {
  char s[] = "Aalborg University", *t;

  t = string_copy(s);

  strcpy(s,"---");      /* destroy s */
  printf("The destroyed original is: %s.\nThe copy is: %s\n", s, t);
  free(t);
  return 0;
}

Program: Output fra programmet.
The destroyed original is: ---.
The copy is: Aalborg University 

Illustration af strncpy (1)
Slide Indhold Stikord
Referencer 

Figur. En illustration af strncpy

Henvisning

Illustration af strncpy (2)
Slide Indhold Stikord
Referencer 

Figur. En illustration af strncpy

Henvisning

Substring ved brug af strncpy
Slide Indhold Stikord
Referencer 

char *strncpy(char *s1, const char *s2, size_t n)

strncpy kan bruges til at udtrække en substreng s1 af en anden streng s2

Herunder udtrækkes "Aalborg University" af en større tekststreng

Program: Et program der udtrækker en substreng af en streng. Det er essentielt at target initialiseres med nultegn, idet det viser sig, at strncpy ikke overfører et nultegn.
#include <stdio.h>
#include <string.h>
#define LEN 25

int main(void) {

  char str[] = "The Aalborg University first year of studies";
  char target[LEN];
  int i; 

  strncpy(target, str+4, 18);
  target[18] = '\0';

  printf("The substring is: %s\nLength: %i\n",
          target, strlen(target));
  
  return 0;
}

Program: Output fra programmet.
The substring is: Aalborg University
Length: 18

Lokalisering af et tegn i en streng - illustration
Slide Indhold Stikord
Referencer 

Figur. En illustration af strchr

Henvisning

Lokalisering af en delstreng i en streng - illustration
Slide Indhold Stikord
Referencer 

Figur. En illustration af strstr

Henvisning

Lokalisering af en delstreng i en streng
Slide Indhold Stikord
Referencer 

char *strstr(const char *s1, const char *s2)

Funktionen strstr lokaliserer en mulig delstreng s2 (eksklusiv nultegnet) i en anden streng s1

Program: Et program der leder efter en delstreng af en streng.
#include <stdio.h>
#include <string.h>

int main(void) {

  char str[] = "The Aalborg University first year of studies",
       *search_result;

  search_result = strstr(str, "University");

  printf("We located: %s\nLength: %i\n",
          search_result, strlen(search_result));
  
  return 0;
}

Program: Output fra programmet.
We located: University first year of studies
Length: 32


Andre emner om tekststrenge

Arrays af tekststrenge
Slide Indhold Stikord
Referencer 

Et array af tekststrenge kan enten forstås som en to dimensionel char tabel eller som en pointer til en char pointer

Program: Et program der allokerer og tilgår et array af tre tekststrenge.
  char *numbers[] = {"one", "two", "three"};
  char ch1, ch2, ch3, ch4;

  ch1 = **numbers;              // 'o'
  ch2 = numbers[0][0];          // 'o'
  ch3 = *(*(numbers+1) + 1);    // 'w'
  ch4 = numbers[2][3];          // 'e'

  printf("ch1 = %c, ch2 = %c, ch3 = %c, ch4 = %c\n", ch1, ch2, ch3, ch4);
  
  return 0;
}

Figur. En illustration af variablen numbers fra ovenstående program

Program: Hele programmet.
#include <stdio.h>

int main(void) {

  char *numbers[] = {"one", "two", "three"};
  char ch1, ch2, ch3, ch4;

  ch1 = **numbers;              // 'o'
  ch2 = numbers[0][0];          // 'o'
  ch3 = *(*(numbers+1) + 1);    // 'w'
  ch4 = numbers[2][3];          // 'e'

  printf("ch1 = %c, ch2 = %c, ch3 = %c, ch4 = %c\n", ch1, ch2, ch3, ch4);
  
  return 0;
}

Program: Output fra programmet.
ch1 = o, ch2 = o, ch3 = w, ch4 = e

Variablen numbers kunne alternativt erklæres og initialiseres som char numbers[][6] = {"one", "two", "three"}

Program: Programmet med alternativ array erklæring.
#include <stdio.h>
#include <ctype.h>

int main(void) {

  /* char *numbers[] = {"one", "two", "three"}; */
  char numbers[3][6] = {"one", "two", "three"};
  char ch1, ch2, ch3, ch4, ch;
  int i;

  ch1 = **numbers;             // 'o'
  ch2 = numbers[0][0];         // 'o'
  ch3 = *(*(numbers+1) + 1);   // 'w'
  ch4 = numbers[2][3];         // 'e'

  printf("ch1 = %c, ch2 = %c, ch3 = %c, ch4 = %c\n", ch1, ch2, ch3, ch4);

  /* Printing the 18 in numbers  characters */
  for(i = 0; i < 18; i++){
    ch = *(&numbers[0][0] + i);
    if (isgraph(ch))
      printf("%c", ch);
    else
      printf("%c", '-');
  }
  printf("\n");

  /* Printing 3 strings */
  for(i = 0; i < 3; i++)
    printf("%s\n", numbers[i]);

  printf("\n");
  return 0;
}

Program: Output fra det alternative program (0 tegn ændret til N, ? er ukendt værdi).
ch1 = o, ch2 = o, ch3 = w, ch4 = e
one---two---three-
one
two
three

Input og output af tekststrenge
Slide Indhold Stikord
Referencer 

Input af teststrenge med scanf har specielle regler

Output af tekststrenge med printf virker som forventet

Program: Et program der indlæser og udskriver en tekststreng med scanf og printf.
// Source file: string-input.c.  Read a string with spaces.
#include <stdio.h>
#include <string.h>

int main(void) {
  char input[100];

  do {
    printf("Enter a string: ");
    scanf("%s", input);
    printf("You entered \"%s\"\n", input);
  }  while (strcmp(input, "exit"));
  
  return 0;
}

Program: Et program der indlæser en line af tekst med gets - usikkert.
// Source file: string-input-gets.c
#include <stdio.h>
#include <string.h>
#define LIMIT 20

int main(void) {
  char input[LIMIT];

  do {
    printf("Enter a string: ");

    gets(input);                            // Dangerous if the input entered 
                                            // is longer than LIMIT
    printf("You entered \"%s\"\n", input);
  }  while (strcmp(input, "exit"));
  
  return 0;
}

Program: Et program der indlæser en line af tekst med fgets - sikkert.
// Source file: string-input-fgets.c
#include <stdio.h>
#include <string.h>
#define LIMIT 20

int main(void) {
  char input[LIMIT];

  do {
    printf("Enter a string: ");

    fgets(input, LIMIT, stdin);             // Safe. Reads newline as well. Terminates with '\0'
                                            
    printf("You entered \"%s\"\n", input);
  }  while (strncmp(input, "exit", 4));
  
  return 0;
}

Funktionen gets(s) læser en linie fra standard input og gemmer det i s.

En lang linie vil kunne forårsage overflow i s - brug fgets i stedet for.

Programparametre
Slide Indhold Stikord
Referencer 

Operativsystemet overfører et array af strenge til main funktionen med information om, hvordan programmet er kaldt

Dette giver muligheder for at overføre programparametre som tekststrenge

Program: Et program der udskriver de overførte programparametre.
/* Echo the command line arguments. */

#include <stdio.h>

int main(int argc, char *argv[]){
   int   i;

   printf("\n  argc = %d\n\n", argc);

   for (i = 0; i < argc; ++i)
      printf("   argv[%d] = %s\n", i, argv[i]);

   return 0;
}

Program: Oversættelse og kørsel af programmet - gcc i MinGW.
> gcc prog-pars.c -o prog-pars
> prog-pars.exe Imperative Programming

  argc = 3

   argv[0] = c:\Users\Kurt\Teaching-material\Imperative-Programming-C\sources\notes-and-c\c\note-examples\strings\prog-pars.exe
   argv[1] = Imperative
   argv[2] = Programming

Konvertering mellem strenge og tal
Slide Indhold Stikord
Referencer 

Det er ofte nødvendigt at kunne konvertere en streng til et tal, og omvendt

  • Konvertering af en streng til et tal

    • Funktionerne atof, atoi, atol alle fra stdlib.h

    • Alternativt kan man læse fra en tekststreng med sscanf

  • Konvertering af et tal til en streng

    • Funktionerne ftoa, itoa, og ltoa er ikke standard funktioner i C

    • Det anbefales at bruge funktionen sprintf fra stdio.h

Program: Eksempel på konvertering af tekststrenge til tal, og fra tal til tesktstrenge - med atoi/atof/atol og sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20

int main(void) {

  /* Strings to numbers: */
  int     i = atoi("1234");
  double  d = atof("123.456");
  long    l = atol("12345678");

  char s1[MAX], s2[MAX], s3[MAX];

  printf("i = %i, d = %f, l = %li.\n",
         i, d, l);
  
  /* Numbers to strings: */
  sprintf(s1, "%i",  i);
  sprintf(s2, "%f",  d);
  sprintf(s3, "%li", l);

  printf("s1 = %s, s2 = %s, s3 = %s.\n",
         s1, s2, s3);

  return 0;
}

Henvisning

Program: Program output.
i = 1234, d = 123.456000, l = 12345678.
s1 = 1234, s2 = 123.456000, s3 = 12345678.

Program: Eksempel på konvertering af tekststrenge til tal, og fra tal til tesktstrenge - med sscanf og sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20

int main(void) {
  int i;
  double d;
  long l;

  char s1[MAX], s2[MAX], s3[MAX];

  /* Strings to numbers med sscanf: */
  sscanf("1234",     "%d",  &i);
  sscanf("123.456",  "%lf", &d);
  sscanf("12345678", "%li", &l);

  printf("i = %i, d = %f, l = %li.\n",
         i, d, l);
  
  /* Numbers to strings: */
  sprintf(s1, "%i",  i);
  sprintf(s2, "%f",  d);
  sprintf(s3, "%li", l);

  printf("s1 = %s, s2 = %s, s3 = %s.\n",
         s1, s2, s3);

  return 0;
}

Program: Program output.
i = 1234, d = 123.456000, l = 12345678.
s1 = 1234, s2 = 123.456000, s3 = 12345678.

Opgaver
Slide Indhold Stikord
Referencer 

Opgave 10.5. Flertals navneord

Skriv et program som oversætter udvalgte engelske navneord fra ental til flertal. Følgende regler skal overholdes:

  1. Hvis et navneord ender i et "y" fjernes "y" og der tilføjes "ies".
  2. Hvis et navneord ender i et "s", "ch" eller "sh" tilføjes et "es".
  3. I alle andre tilfælde tilføjes et "s" til navneordet.

Udskriv hvert navneord i både ental og flertal.

Som altid skal du designe en funktion med et passende navn, og med parametre (input og evt. output). Og som altid laver vi top-down programmering ved trinvis forfinelse. Ønsker du at bruge returværdien af funktionen til noget?

Afprøv dit program på følgende engelske navneord:

  • chair dairy boss circus fly dog church clue dish

Denne opgave svarer til opgave 5 side 532 i 6. udgave af lærebogen

Hints: Måske er funktionen strrchr fra string.h nyttig i denne opgave. Den søger efter et tegn fra bagenden af strengen. Husk også at du blot kan tilgå tegn i en tekststreng med array subscripting operatoren: str[i]. Du kan teste om et tegn i din streng svarer til et bestemt tegn: str[i] == 'y'.

Opgave 10.5. Længste fælles endelse af to ord

Skriv et program med en funktion der finder og returnerer det længste fælles endelse (suffix) af to ord.

Funktionen skal have tre parametre. De to ord (to tekststrenge) skal overføres som input parametre. Den længste fælles endelse skal returneres i en output parameter (også en tekststreng). (Hvordan markerer du forskellen på en input parameter og en output parameter, som begge er tekststrenge?) Overvej hvordan der bliver allokeret plads til tesktstrengen med den fælles endelse (vil du bruge statisk eller dynamisk allokering?).

Eksempelvis er "logi" den længste fælles endelse af ordene "datalogi" og "biologi". Og den længste fælles endelse af "program" og "diagram" er "gram".

Denne opgave svarer til opgave 8 side 533 i 6. udgave af lærebogen


Samlede referencer
Indhold Stikord
A tutorial on character code issues
Unicode tegntabeller
Tidligere program der genererer ASCII tegntabel
Tidligere programmer
Tidligere program
string.h oversigt
printf familien i IO lektionen

 

Kapitel 10: Tegn og Tekststrenge
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: 7. november 2017, 12:04:59