Index over opgaver i denne lektion   Alfabetisk indeks   Kursets hjemmeside   

Opgaver og løsninger
Tegn og Tekststrenge


10.1   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å.

Løsning

Her er min version af strrev:

#include <stdio.h>
#include <string.h>

char *strrev(char *str);

int main(void) {

  char str[] = "abcd";
  printf("%s\n", strrev(str));

  strcpy(str, "abc");
  printf("%s\n", strrev(str));

  strcpy(str, "ab");
  printf("%s\n", strrev(str));

  strcpy(str, "a");
  printf("%s\n", strrev(str));

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

char *strrev(char *str){
  int i = 0,
      j = strlen(str) - 1;
  char temp;

  while (i < j){
   
    // Swap char number i and j in str:
    temp = str[j];
    str[j] = str[i];
    str[i] = temp;

    i++; j--;
  }

  return str;
}

Jeg tester funktionen med forskellige strenge, af forskellige længder, herunder den tomme streng

Jeg får følgende program output:

dcba
cba
ba
a


10.2   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.

Løsning

Her er en mulig løsning med forskellige afprøvninger af vores egen strcmp:

#include <stdio.h>

int strcmp(const char *str1, const char *str2);
void pr(char *s, char *t, int r);

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


/* Return the string compare value of str1 and str2. 
   As a precondition, neither of the strings are assumed to be NULL */
int strcmp(const char *str1, const char *str2){
  if (str1[0] == '\0' && str2[0] == '\0')         /* Both empty strings */
     return 0;
  else if (str1[0] != '\0' && str2[0] == '\0')    /* str1 non-empty, str2 is empty */
     return 1;
  else if (str1[0] == '\0' && str2[0] != '\0')    /* str2 non-empty, str1 is empty */
     return -1;
  else if (str1[0] < str2[0])                     /* first char of str1 is smaller than first char of str2 */
     return -1;
  else if (str1[0] > str2[0])                     /* first char of str2 is smaller than first char of str1 */
     return 1;
  else                                            /* (str1[0] == str2[0]). Recur! */                
     return strcmp(str1+1, str2+1);
}


10.3   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:

Alloker plads til disse i en passende array af tekststrenge.

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'.

Løsning

Her er en løsning på opgaven. Læg mærke til at problemet løses i en funktion med et godt navn, og med gode parametre, og en velvalgt returværdi. Det er simpelthen ikke godt nok blot at programmere funktionaliteten i main! Jeg vælger at allokere lager med malloc i funktionen. Der er andre gode alternative løsninger. Læg mærke til at jeg bruger almindelig array subscripting notation for at tilgå tegnene i noun i funktionen plural_noun_of. Læg også mærke til at jeg er omhyggelig med at checke at strengen ikke er for kort (lgt >= ...):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *plural_noun_of(const char* noun);

int main(void) {
  char *words[] = {"chair", "dairy", "boss", "circus", "fly", "dog", "church", "clue", "dish"},
       *plural_form;
  int i;

  for(i = 0; i < (sizeof(words) / sizeof(char *)); i++){
    plural_form = plural_noun_of(words[i]);
    printf("Plural of %s is %s\n", words[i], plural_form);
    free(plural_form);
  }
  
  return 0;
}

char *plural_noun_of(const char* noun){
  char *res;
  int lgt = strlen(noun);

  res = malloc(lgt + 3);

  if (res == NULL){
     printf("Out of memory. Bye.");
     exit(1);
  }

  if (lgt >= 1 && noun[lgt-1] == 'y'){
    strncpy(res, noun, lgt-1);
    res[lgt-1] = '\0';   /* If omitted, strcat will not work correctly!!! */
    strcat(res, "ies");
  } 
  else if ((lgt >= 1 && noun[lgt-1] == 's') ||
           (lgt >= 2 && noun[lgt-2] == 'c' && noun[lgt-1] == 'h') ||
           (lgt >= 2 && noun[lgt-2] == 's' && noun[lgt-1] == 'h')) {
    strcpy(res, noun);
    strcat(res, "es");
  }
  else {
    strcpy(res, noun);
    strcat(res, "s");
  }
  return res;
}

Output fra dette program er:

Plural of chair is chairs
Plural of dairy is dairies
Plural of boss is bosses
Plural of circus is circuses
Plural of fly is flies
Plural of dog is dogs
Plural of church is churches
Plural of clue is clues
Plural of dish is dishes


10.4   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

Løsning

Her er min løsning. I denne opgave sender jeg et allerede allokeret array med som 3. parameter til longest_common_prefix. Derfor bruger jeg ikke malloc. Jeg vælger at returnere en pointer til dette array fra longest_common_prefix, hvilket ikke er nødvendigt - men blot fiks i situationen. Mange C programmører ville vælge at finde endelsen i word1 (eller word2), og blot returnere en pointer til endelsen inde i word1 (eller word2).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 25
#define NUMBER_OF_WORDS 4

void rinse_string(char str[], int n);
char *longest_common_suffix(const char *word1, const char *word2, char *suffix);

int main(void) {

  /* An array of pair of char pointers. Each pair is a an array of two elements. */
  char *words[][2] = 
         {
           {"procrastination", "destination"},
           {"globally", "internally"},
           {"gloves", "dove"},
           {"girl", "girl"}
         },
       str[MAX_WORD_LENGTH];
  int i;

  for(i = 0; i < NUMBER_OF_WORDS; i++){
    rinse_string(str, MAX_WORD_LENGTH);
    printf("Longest common suffix of %s and %s is %s\n", words[i][0], words[i][1], 
           longest_common_suffix(words[i][0], words[i][1], str));
  }
  
  return 0;
}

char *longest_common_suffix(const char *word1, const char *word2, char *suffix){
  int i, j, c = 0;

  i = strlen(word1)-1; j = strlen(word2)-1;

  while (i >= 0 && j >= 0 && word1[i] == word2[j]){
    i--; j--; c++;
  }

  strncpy(suffix, word1 + i + 1, c + 1);  // includes trailing null char.

  return suffix;
}

/* Put spaces in the char array str, of length n*/
void rinse_string(char str[], int n){
  int j;
  for (j = 0; j < n; j++) str[j] = ' ';  
}

Output fra programmet er følgende:

Longest common suffix of procrastination and destination is stination
Longest common suffix of globally and internally is ally
Longest common suffix of gloves and dove is 
Longest common suffix of girl and girl is girl


Genereret: Fredag 5. november 2021, 09:47:46