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:
-
pw_04_matrices_strings/
- AUTHORS
-
matrices/
- main.c
- Makefile
- matrix.c
- matrix.h
-
strings/
-
jumbled_text/
- main.c
- Makefile
- mix.c
- mix.h
-
substrings/
- main.c
- Makefile
-
The AUTHORS
file
must contains the following information.
First Name
Family Name
Login
Email Address
For instance:
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:
This matrix can be stored in a single-dimensional array as follows:
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]
i
is the row number of the cell we want to access.j
is the column number of the cell we want to access.cols
is the total number of columns.
This method is known as row-major order.
Provided Code
Four files are provided:
-
Makefile
: it can be used to compile your code. -
matrix.c
: it contains the functions you will write. You are supposed to complete this file. -
matrix.h
: the header ofmatrix.c
. -
main.c
: it contains the main function used to test your functions. You are supposed to complete this file.
So first, the 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.
#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.
#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.
#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);
-
s
= the name of the matrix to be printed. -
m
= the matrix to be printed. -
rows
= the number of rows in the matrix. -
cols
= the number of columns in the matrix.
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[]);
-
m
= the matrix to be transposed. -
rows
= the number of rows in the matrix. -
cols
= the number of columns in the matrix. -
r
= the output matrix that will store the result.
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[]);
-
m1
= the first matrix to be added. -
m2
= the second matrix to be added. -
rows
= the number of rows of the two matrices. -
cols
= the number of columns of the two matrices. -
r
= the output matrix that will store the result.
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[]);
-
m1
= the first matrix to be multiplied. -
m2
= the second matrix to be multiplied. -
r1
= the number of rows in the first matrix. -
c1
= the number of columns in the first matrix that is also the number of rows of the second matrix. -
r1
= the number of columns in the second matrix. -
r
= the output matrix that will store the result.
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:
- We can pass two parameters to you program. They are both strings of characters.
- The two strings must not contain accented letters.
- Your program must find if the second string is contained in the first one.
-
If the second string is not found,
your program must print
"Not found!"
. -
If the second string is found,
your program must print the first string
and the
^
symbol just under the first occurrence of the second string. - Your program must be case-sensitive.
-
When the number of strings passed as parameters
is different from two,
your program must print an error message
and exit with the error code 1.
To do so, you can use the
errx()
function of the standard library. To check the return code of your program you can use the following command:echo $?
-
Your program will be made up of two files:
-
main.c
that contains all the functions of your program. You are free to write all the functions you need. -
Makefile
that compiles yourfile and generates the executable file.
-
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.
- It will contain your main function.
- It must not contain any other functions than the main function.
- It can contain some include directives.
About the mix.c
file.
- It will contain all your functions (but for the main function).
- You are free to write all the functions you need.
-
It must contain a
mix()
function that will be called from the main function (see below for its prototype).
About the mix.h
file.
-
It is the header of the
mix.c
file. -
It is used to export the
mix()
function only.
About the Makefile.
- Make it simple.
- It must compile your source files and generate the executable file.
Prototype of the mix()
function:
void mix(char s[]);
The mix()
function converts a string of characters
into jumble text.
-
s
: Holds a string of characters to be converted into jumbled text.
This function must modify the string passed as parameter (the original string will be lost). This original string can contain:
- small letters without accents,
- capital letters without accents,
- digits,
- spaces,
- punctuation marks.
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 first letter of a word does not change.
- The last letter of a word does not change.
- If the length of a word is lower than or equal to three, the word does not change.
-
Two letters of a word are swapped by pair successively
from the second letter to the last but one
(for odd numbers, the last but one letter does not change).
For instance:
-
"abcd"
becomes"acbd"
. -
"abcde"
becomes"acbde"
. -
"abcdefg"
becomes"acbedfg"
. -
"abcdefghij"
becomes"acbedgfihj"
.
-
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.