Practical Programming David Bouchet
Practical Work #4

Matrices and Strings

Submission

Due Date

By Friday 23 November 2018 23:42

Directory Hierarchy

Create you git repository (replace john.smith by your own login).

                
                    $ git clone git@git.cri.epita.net:p/2022-spe-tp/tp04-john.smith
                
            

It must contain the following files and directories:

The AUTHORS file must contains the following information.

AUTHORS
                
                    First Name
                    Family Name
                    Login
                    Email Address
                
            

For instance:

AUTHORS
                
                    John
                    Smith
                    john.smith
                    john.smith@epita.fr
                
            

Be careful, if you do not follow all the given instructions, no point will be given to your answers.

Basic Matrix Manipulations

Do not use pointers in this section.

Introduction

The purpose of this part is to introduce good practices on matrix manipulations.

There are many ways to represent matrices in the C language. Experience has shown that in most cases, it is preferable to consider matrices as single-dimensional arrays. This way, matrices are stored in contiguous memory space, thus improving performances.

To explain how it works, let us consider a 3x3 matrix:

Multi-Dimensional Matrix

This matrix can be stored in a single-dimensional array as follows:

Single-Dimensional Matrix

Accessing a cell can be done by converting the two indices of the two-dimensional array into only one index.

array[i][j] = array[i * cols + j]

This method is known as row-major order.

Provided Code

Four files are provided:

So first, the Makefile:

Makefile
                
                    # Makefile
                     
                    CC = gcc -fsanitize=address
                    CPPFLAGS = -MMD
                    CFLAGS = -Wall -Wextra -std=c99 -O0 -g
                    LDFLAGS =
                    LDLIBS =
                     
                    OBJ = matrix.o main.o
                    DEP = ${OBJ:.o=.d}
                     
                    all: main
                     
                    main: ${OBJ}
                     
                    clean:
                    	${RM} ${OBJ} ${DEP} main
                     
                    -include ${DEP}
                     
                    # END
                
            

Then, the matrix.c file.

matrix.c
                
                    #include <stdio.h>

                    void print_matrix(char s[], double m[], size_t rows, size_t cols)
                    {
                        // TODO
                    }

                    void transpose(double m[], size_t rows, size_t cols, double r[])
                    {
                        // TODO
                    }

                    void add(double m1[], double m2[], size_t rows, size_t cols, double r[])
                    {
                        // TODO
                    }

                    void mul(double m1[], double m2[], size_t r1, size_t c1, size_t c2, double r[])
                    {
                        // TODO
                    }
                
            

Next, the matrix.h header file.

matrix.h
                
                    #ifndef MATRIX_H
                    #define MATRIX_H
                     
                    void print_matrix(char s[], double m[], size_t rows, size_t cols);
                    void transpose(double m[], size_t rows, size_t cols, double r[]);
                    void add(double m1[], double m2[], size_t rows, size_t cols, double r[]);
                    void mul(double m1[], double m2[], size_t r1, size_t c1, size_t c2, double r[]);
                    
                    #endif
                
            

Finally, the main.c file.

main.c
                
                    #include <stdio.h>
                    #include "matrix.h"
                    
                    #define ROWS1 1
                    #define COLS1 2
                    double m1[] =
                    {
                        1, 2
                    };
                    
                    #define ROWS2 2
                    #define COLS2 2
                    double m2[] =
                    {
                        1, 2,
                        3, 4
                    };
                    
                    #define ROWS3 3
                    #define COLS3 2
                    double m3[] =
                    {
                        1, 2,
                        3, 4,
                        5, 6
                    };
                    
                    #define ROWS4 4
                    #define COLS4 3
                    double m4[] =
                    {
                        1, 0, 3,
                        1, 2, 0,
                        0, 2, 3,
                        1, 0, 3
                    };
                    
                    #define ROWS5 3
                    #define COLS5 4
                    double m5[] =
                    {
                        1, 2, 3, 4,
                        5, 6, 7, 8,
                        9, 10, 11, 12,
                    };
                    
                    // Results for the transpositions.
                    double m1_tr[ROWS1 * COLS1];
                    double m2_tr[ROWS2 * COLS2];
                    double m3_tr[ROWS3 * COLS3];
                    double m4_tr[ROWS4 * COLS4];
                    double m5_tr[ROWS5 * COLS5];
                    
                    // Results for the additions.
                    double m3_plus_m3[ROWS3 * COLS3];
                    double m4_plus_m5tr[ROWS4 * COLS4];
                    double m5_plus_m4tr[ROWS5 * COLS5];
                    
                    // Results for the multiplications.
                    double m2_times_m2[ROWS2 * COLS2];
                    double m4_times_m5[ROWS4 * COLS5];
                    double m5_times_m4[ROWS5 * COLS4];
                    
                    int main()
                    {
                        print_matrix("m1", m1, ROWS1, COLS1);
                        print_matrix("m2", m2, ROWS2, COLS2);
                        print_matrix("m3", m3, ROWS3, COLS3);
                        print_matrix("m4", m4, ROWS4, COLS4);
                        print_matrix("m5", m5, ROWS5, COLS5);
                    
                        // TODO
                        //
                        // Add some code to test your
                        // transpose(), add() and mul() functions.
                    
                        return 0;
                    }
                
            

Printing Matrices

In this part, you will write the print_matrix() function that prints the contents of a matrix.

                
                    void print_matrix(char s[], double m[], size_t rows, size_t cols);
                
            

The printing will be done in a straightforward way (i.e. row by row). You should use the printf() function with the %4g format. For instance:

                
                    m1 =
                        1   2   3   4
                        5   6   7   8
                        9  10  11  12
                
            

Write the print_matrix() function in the matrix.c file and test it by using the main.c file. Some code is already provided in the main.c file. For this first function you do not have to modify it.

The expected results are as follows:

                
                    $ ./main
                    m1 = 
                       1   2
                    m2 = 
                       1   2
                       3   4
                    m3 = 
                       1   2
                       3   4
                       5   6
                    m4 = 
                       1   0   3
                       1   2   0
                       0   2   3
                       1   0   3
                    m5 = 
                       1   2   3   4
                       5   6   7   8
                       9  10  11  12
                
            

Transposing Matrices

In this part, you will write the transpose() function that switches the rows and columns in a matrix (see Transpose).

                
                    void transpose(double m[], size_t rows, size_t cols, double r[]);
                
            

Write the transpose() function in the matrix.c file and add some code in the main.c file in order to test it. The matrices used for testing are already defined as global variables. So, just write some instructions to transpose the matrices and print the results.

The expected results are as follows (the first part has been snipped):

                
                    $ ./main
                    m1 = 
                       1   2
                    # ... snip ...
                    m1_tr = 
                       1
                       2
                    m2_tr = 
                       1   3
                       2   4
                    m3_tr = 
                       1   3   5
                       2   4   6
                    m4_tr = 
                       1   1   0   1
                       0   2   2   0
                       3   0   3   3
                    m5_tr = 
                       1   5   9
                       2   6  10
                       3   7  11
                       4   8  12
                
            

Adding Matrices

In this part, you will write the add() function that adds two matrices that have the same dimensions (see Matrix addition).

                
                    void add(double m1[], double m2[], size_t rows, size_t cols, double r[]);
                
            

Write the add() function in the matrix.c file and add some code in the main.c file in order to test it. The matrices used for testing are already defined as global variables. So, just write some instructions to add the matrices and print the results.

The expected results are as follows (the first part has been snipped):

                
                    $ ./main
                    m1 = 
                       1   2
                    # ... snip ...
                    m3_plus_m3 = 
                       2   4
                       6   8
                      10  12
                    m4_plus_m5tr = 
                       2   5  12
                       3   8  10
                       3   9  14
                       5   8  15
                    m5_plus_m4tr = 
                       2   3   3   5
                       5   8   9   8
                      12  10  14  15
                
            

Multiplying Matrices

In this part, you will write the mul() function that multiplies two matrices. The number of columns in the first matrix must be equal to the number of rows in the second matrix (see Matrix multiplication).

                
                    void mul(double m1[], double m2[], size_t r1, size_t c1, size_t c2, double r[]);
                
            

Write the mul() function in the matrix.c file and add some code in the main.c file in order to test it. The matrices used for testing are already defined as global variables. So, just write some instructions to multiply the matrices and print the results.

The full expected results are as follows:

                
                    $ ./main 
                    m1 = 
                       1   2
                    m2 = 
                       1   2
                       3   4
                    m3 = 
                       1   2
                       3   4
                       5   6
                    m4 = 
                       1   0   3
                       1   2   0
                       0   2   3
                       1   0   3
                    m5 = 
                       1   2   3   4
                       5   6   7   8
                       9  10  11  12
                    m1_tr = 
                       1
                       2
                    m2_tr = 
                       1   3
                       2   4
                    m3_tr = 
                       1   3   5
                       2   4   6
                    m4_tr = 
                       1   1   0   1
                       0   2   2   0
                       3   0   3   3
                    m5_tr = 
                       1   5   9
                       2   6  10
                       3   7  11
                       4   8  12
                    m3_plus_m3 = 
                       2   4
                       6   8
                      10  12
                    m4_plus_m5tr = 
                       2   5  12
                       3   8  10
                       3   9  14
                       5   8  15
                    m5_plus_m4tr = 
                       2   3   3   5
                       5   8   9   8
                      12  10  14  15
                    m2_times_m2 = 
                       7  10
                      15  22
                    m4_times_m5 = 
                      28  32  36  40
                      11  14  17  20
                      37  42  47  52
                      28  32  36  40
                    m5_times_m4 = 
                       7  10  24
                      19  26  60
                      31  42  96
                
            

Strings

Do not use pointers in this section.

Substrings

Let us start with basic string manipulations. In this section, you will write a program that has the following behavior.

                
                    $ ./main "Hello World!" World
                    Hello World!
                          ^
                    $ ./main "Hello World!" Warld
                    Not Found!
                    $ ./main "Hello World!" "o W"
                    Hello World!
                        ^
                    $ ./main "Hello World!" "ld"
                    Hello World!
                             ^
                    $ ./main "Hello World!" o
                    Hello World!
                        ^
                    $ ./main "Sweet Child O' Mine" child
                    Not Found!
                    $ ./main "Sweet Child O' Mine" Child
                    Sweet Child O' Mine
                          ^
                    $ ./main 
                    main: Usage: str1 str2
                    $ echo $?
                    1
                
            

Additional information:

Jumbled Text

Can you read this?

Accroidng to a rseaecrehr at Cmarbdige Uinevsrtiy, it deosn't mtaetr in waht odrer the lteetrs in a wrod are, the olny ipmroatnt tihng is taht the frist and lsat lteetrs be at the rgiht palce. The rset can be a ttoal mses and you can sitll raed it wtiohut porlbem. Tihs is bceuase the hmuan mnid deos not raed eevry lteetr by istlef but the wrod as a wohle.

You were certainly able to read it. If not, here is the correct version:

According to a researcher at Cambridge University, it doesn't matter in what order the letters in a word are, the only important thing is that the first and last letters be at the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself but the word as a whole.

In this section, you will write a program that generates jumbled text. That is to say, it will keep only the first and last letters of each word in the right place and jumble the other letters up.

Your program will be made up of four files: main.c, mix.c, mix.h, Makefile.

About the main.c file.

About the mix.c file.

About the mix.h file.

About the Makefile.

Prototype of the mix() function:

                
                    void mix(char s[]);
                
            

The mix() function converts a string of characters into jumble text.

This function must modify the string passed as parameter (the original string will be lost). This original string can contain:

Characters that are not letters will be called separators. Two words are separated by at least one separator. Only the following separators are allowed:

                
                    char separator[] = " ,;:!?./§%*$=+)@_-('&1234567890\"\r\n"
                
            

When mixing the letters of a word, you have to follow the instructions below:

The user can pass the string to be converted as a parameter. The original and converted strings are both printed. For instance:

                
                    $ ./main "Hello World!"
                    Hello World!
                    Hlelo Wrold!
                    $ ./main "I am not a number! I'm a free man!"
                    I am not a number! I'm a free man!
                    I am not a nmuebr! I'm a fere man!
                    $ ./main "I was born ready!"
                    I was born ready!
                    I was bron raedy!
                
            

If the number of parameters that are passed in is different from one, your program must use a default text. You are free to use the text you want. For instance:

                
                    $ ./main
                    This is the default text.
                    Tihs is the dfeualt txet.
                    $ ./main Hello World
                    This is the default text.
                    Tihs is the dfeualt txet.