Umeå Universitet
Institutionen för datavetenskap
Programmeringsteknik för tekniska fysiker
Niklas Frykholm, 24 februari 1999
Här är några förslag på lösningar till uppgifterna. Kom dock ihåg att det alltid finns mer än ett sätt att lösa en uppgift.
Det rättade programmet ser ut som.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char **s, int n);
/* Detta program läser in tre strängar och skriver ut
dem i sorterad ordning. */
int main(void)
{
char *s[3];
int i;
s[0] = malloc(100);
s[1] = malloc(100);
s[2] = malloc(100);
for (i=0; i<3; i++)
scanf("%s", s[i]);
sort(s,3);
for (i=0; i<3; i++)
printf("%s\n", s[i]);
free(s[0]); free(s[1]); free(s[2]);
return 0;
}
/* Sorterar en vektor med strängar i bokstavsordning. */
void sort(char **s, int n)
{
int i, j;
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
if (strcmp(s[i],s[j])>0) {
char *temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int akt_vaningar(int vaningsstopp[], int antal);
int main(void)
{
int stopp, sum, *vaningar, i;
printf("Hur många stopp? ");
scanf("%d", &stopp);
vaningar = malloc(stopp*sizeof(int));
for (i=0; i<stopp; i++)
scanf("%d", &vaningar[i]);
sum = akt_vaningar(vaningar, stopp);
printf("Hissen har sammanlagt åkt %d våningar.\n", sum);
if (sum >10000)
printf("Det är dags för service.\n");
return 0;
}
int akt_vaningar(int vaningsstopp[], int antal)
{
int i, sum = 0;
for (i=1; i<antal; i++)
sum += abs(vaningsstopp[i] - vaningsstopp[i-1]);
return sum;
}
Jag har valt att allokera vektorn med våningsstopp dynamiskt (med malloc) det gör att vi kan göra den precis lagom stor.
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main(void)
{
char *s, *p;
s = malloc(100*sizeof(char));
assert(s);
scanf("%s", s);
p = s;
while (*p)
p++;
p--;
while (p>=s) {
putchar(*p);
p--;
}
free(s);
return 0;
}
En annan idé är att sätta p = s + strlen(s) - 1; för att direkt hoppa till slutet av strängen.
Problemet kan lösas på flera olika sätt, bl a genom att rita bilder eller genom att räkna på adresser. Jag visar den algebraiska metoden eftersom den är enklast att skriva ned. Kom ihåg de grundläggande räknereglerna.
a[i] <=> *(a+i) &*p <=> *&p <=> p
*(i[1] + 1) <=> i[1][1] <=> i[0][0] + 4 <=> *(i[0] + 0) + 4 <=> <=> *i[0] + 4 <=> **(i+0) + 4 <=> **i + 4 <=> 5 + 4 <=> 9
#include <stdio.h>
int full_hand(int hand[5]);
int main(void)
{
int h[5], i;
printf("Mata in fem kortnr: ");
for (i=0; i<5; i++)
scanf("%d", &h[i]);
if (full_hand(h))
printf("Du har kåk.\n");
else
printf("Du har inte kåk.\n");
return 0;
}
int full_hand(int hand[5])
{
/* Håller reda på hur många kort vi sett av varje valör. */
int count[13] = {0};
int i;
int treval = 0, tvaval = 0;
/* Om vi numrerar korten så att 0 är hjärter ess 1 hjärter två, ..
13 klöver ess, 14 klöver två osv, kan vi beräkna ett korts
valör som kortnr % 13. */
for (i=0; i<5; i++)
count[hand[i]%13]++;
/* Om count innehåller en valör med tre kort och en med två kort
har vi en kåk. */
for (i=0; i<13; i++) {
if (count[i] == 3)
treval = 1;
if (count[i] == 2)
tvaval = 1;
}
return treval && tvaval;
}
En annan metod än att använda en vektor för att räkna hur många kort vi har av varje valör är att först sortera korten i handen i storleksordning och sedan kontrollera.
if ( hand[0]%13 == hand[1]%13 && hand[3]%13 == hand[4]%13 &&
(hand[2]%13 == hand[1]%13 || hand[2]%13 == hand[3]%13))
Men det är litet krångligare...
#include <stdio.h>
void print_code(char *s);
void print_code_rec(char *s);
int main(void)
{
char s[100];
printf("Skriv en sträng: ");
scanf("%s", s);
printf("print_code: ");
print_code(s);
printf("\nprint_code_rec: ");
print_code_rec(s);
printf("\n");
return 0;
}
void print_code(char *s)
{
for (;*s;s++)
putchar( *s == 'Z' ? 'A' : *s + 1);
}
void print_code_rec(char *s)
{
if (*s) {
putchar(*s =='Z' ? 'A' : *s + 1);
print_code_rec(s+1);
}
}
Notera de luriga skrivsätten i for-loopen och putchar-satsen. Det är en god övning att försöka förstå hur dessa fungerar.
A är deklarerad som en vektor eftersom vi inte på förhand vet hur många rader matrisen innehåller (det bestäms av värdet på n). Se sid 279 i kursboken. Om vi vill komma åt elementet på rad i, kolumn j får vi lov att skriva A[i*n + j]. Det fungerar eftersom elementen ligger efter varandra i minnet.
c är ett argument eftersom funktioner inte kan returnera verktorer. När vi anropar en funktion med en vektor är det egentligen en pekare som skickas. Det betyder att de ändringar vi gör i c kommer att påverka variabeln i den anropande funktionen (call-by-reference). Paramtern c kan därför användas för att returnera resultatet.
#include <stdio.h>
void matrix_vector(int n, double A[], double b[], double c[]);
int main(void)
{
double A[3][3] = { {1, 0, 1}, {2, 2, 2}, {0, 0, 1}};
double b[3] = {1, 1, 1}, c[3];
matrix_vector(3, &A[0][0], b, c);
printf("c = {%lf, %lf, %lf}\n", c[0], c[1], c[2]);
return 0;
}
void matrix_vector(int n, double A[], double b[], double c[])
{
int i, k, sum;
for (i=0; i<n; i++) {
sum = 0;
for (k=0; k<n; k++)
sum += A[i*n + k] * b[k];
c[i] = sum;
}
}
Jag använder den algebraiska metoden, som på förra uppgiften.
*p1 <=> *&i[0] <=> i[0] *p2 <=> *&i[2] <=> i[2] p1[3] <=> *(p1 + 3) <=> *(&i[0] + 3) <=> *(i + 3) <=> i[3] p2[-1] <=> *(p2 - 1) <=> *(&i[2] - 1) <=> *(&*(i+2) -1) <=> *(i + 1) <=> i[1] *(p1 + 1) <=> *(&i[0] + 1) <=> *(&*(i+0) + 1) <=> *(i + 1) <=> i[1]
Raden p2[-1] = 13 sätter alltså i[1] till 13. Det är detta värde som sedan skrivs ut när vi skriver ut *(p1+1).
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void read_fields(char *fields[7]);
int main(void)
{
char *f[7];
char *head[7] = {"Namn:", "Användarnamn:", "Lösenord (kodat):",
"Användar-ID:", "Grupp-ID:", "Hemkatalog:",
"Skalprogram:"};
int i;
read_fields(f);
/* %-20s är en kod för att få strängen litet snyggare utskriven.
Läs i kapitel 11 om sådana koder. */
for (i=0; i<7; i++)
printf("%-20s %s\n", head[i], f[i]);
/* Jag slarvar litet och gör inte free här.*/
return 0;
}
void read_fields(char *fields[7])
{
int i, c;
for (i=0; i<7; i++) {
/* Vi använder en buffert för att lagra undan den sträng vi läser.
När vi har läst in hela bufferten allokerar vi en lagom stor pekare
och kopierar bufferten dit. */
char buffer[200], n=0;
while (1) {
c = getchar();
if (c == ':' || c=='\n' || c==EOF)
break;
buffer[n] = c;
n++;
}
buffer[n] = 0;
fields[i] = malloc((n+1)*sizeof(char));
assert(fields[i]);
strcpy(fields[i], buffer);
}
}
Testkör programmet genom att skriva.
ypcat passwd | grep niklasf | a.out
Prova att byta ut niklasf mot ditt eget användarnamn.
© Niklas Frykholm, februari 1999