Chapter 4

Exercise 4-1

main.c

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

int strrindex(const char s[], const char t[]);


int main()
{
    char *s;
    char *t;
    long unsigned ns, nt;

    s = t = NULL;
    ns = nt = 0;
    while (getline(&s, &ns, stdin) > 0){
        if (getline(&t, &nt, stdin) <= 0){
            printf("getline: error reading 2nd line\n");
            return 1;
        }
        printf("position of last occurence: %d\n", strrindex(s, t));
    }

    return 0;
}

int strrindex(const char s[], const char t[])
{
    int i_start; /* initial position to start comparing*/
    int i, j, k;
    
    i_start = strlen(s) - strlen(t);
    for (i = i_start; i >= 0; --i) {
        for (k = i, j = 0; s[k] == t[j] && t[j] != '\n' && t[j] != '\0' ; ++k, ++j);
        if (t[j] == '\n' || t[j] == '\0'){
            return i;
        }
    }
    return -1;
}

Compilation and run:

$ gcc main.c
$ ./a.out
Knowledge is power
ow
position of last occurence: 14

Exercise 4-2

main.c

#include <stdio.h>
#include <ctype.h>
#include <math.h>

double atof(const char s[]);

int main()
{
    char *s;
    long unsigned n;

    s = NULL;
    n = 0;
    while (getline(&s, &n, stdin) > 0){
        printf("%f\n", atof(s));
    }
    return 0; 
}

double atof(const char s[])
{
    /* ignore trailing whitespaces and get sign */
    int i, sign;
    for (i = 0; s[i] == ' '; ++i);
    sign = s[i] == '-' ? -1 : 1;
    if (s[i] == '-' || s[i] == '+'){
        ++i;
    }

    /* get absolute integer value */
    double val = 0;
    while (isdigit(s[i])){
        val = 10 * val + (s[i] - '0');
        ++i;
    }

    /* add decimals */
    if (s[i] == '.') {
        int dec = 1;
        ++i;
        while (isdigit(s[i])) {
            val = 10 * val + (s[i] - '0');
            dec *= 10;
            ++i;
        }
        val /= dec;
    }

    /* add exponents */
    if (s[i] == 'e' || s[i] == 'E') {
        int expsign, exp=0;
        ++i;
        expsign = (s[i] == '-') ? -1 : 1;
        if (s[i] == '-' || s[i] == '+') 
            ++i;
        while (isdigit(s[i])) {
            exp = 10 * exp + (s[i] - '0');
            ++i;
        }
        val = val * pow(10.0, expsign * exp);
    }
    return  sign * val;
}

Compilation and run:

$ gcc main.c
$ ./a.out
    234
234.000000
0.123
0.123000
1234.
1234.000000
123.123
123.123000
123.2e4
1232000.000000
123.123e-3
0.123123
-1234
-1234.000000
-1234.0
-1234.000000
-1234.
-1234.000000
-1234.2e4
-12342000.000000
-1234.234e4
-12342340.000000
-1234.123e-4
-0.123412

Notes:

  • The option -lm tell GCC to link the math library. This is necesary because the math library is not included by default.

Note

In general, it is usual to start library file names with “lib”. This way, -lname search for a library file named libname.so in a specific list of directories. We can add new directories to the list using the option -L/another/path/to/search.

If we add the option -static it searchs and links static libraries instead (libname.a).

The standard library libc.so is always included by default.

Exercises 4-3, 4-4, 4-5, 4-6

main.c

#include "tokenizer.h"
#include "stack.h"
#include "variables.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXOP 32

/* reverse Polish calculator */
int main() 
{
    int type;
    char s[MAXOP];
    double op1, op2;
    int iop2;
    char var;
    double vprinted;
    int mssg;

    mssg = 0;
    initvar();

    while ((type = gettoken(s, MAXOP)) != EOF) {
        switch (type) {
        case NUM:
            op1 = atof(s);
            if (push(op1) == -1){
                printf("error: full stack, can't push %f \n", op1);
                mssg = 1;
            }
            break;
        case VAR:
            var = s[0];
            if (hasvalue(var)){
                if (push(getvar(var)) == -1){
                    printf("error: full stack, can't push %f \n", op1);
                    mssg = 1;
                }
            }else{
                setvar(var, pop());
            }
            break;
        case '_':
            op1 = vprinted;
            if (push(op1) == -1){
                printf("error: full stack, can't push %f \n", op1);
                mssg = 1;
            }
            break;
        case '\n':
            if (!mssg){
                printvar();
                printstack();
            }else{
                mssg = 0;
            }
            printf("> ");
            vprinted = peek();
            break;
        case '+':
            push(pop() + pop());
            break;
        case '*':
            push(pop() * pop());
            break;
        case '-':
            op2 = pop();
            push(pop() - op2);
            break;
        case '/':
            op2 = pop();
            if (op2 != 0.0){
                push(pop() / op2);
            }else{
                printf("error: division by 0\n");
                mssg = 1;
            }
            break;
        case '%':
            iop2 = (int) pop();
            if (iop2 != 0){
                push((int)pop() % iop2);
            }else{
                printf("error: division by 0\n");
                mssg = 1;
            }
            break;
        case POW:
            op2 = pop();
            push(pow(pop(), op2));
            break;
        case EXP:
            push(exp(pop()));
            break;
        case SIN:
            push(sin(pop()));
            break;
        case SWP:
            swap();
            break;
        case DUP:
            dup();
            break;
        case DEL:
            pop();
            break;
        case CLR:
            clearstack();   
            break;
        case ERR:
            printf("error: input ignored\n");
            mssg = 1;
            break;
        default:
            printf("error: Invalid input '%s'\n", s);
            mssg = 1;
            break;
        }
    }
    /* we should free memory allocated with getline in myio.c here */
}
  • getopt was vulnerable to buffer overflows, wo we added the n parameter and change its name to gettoken. Same as getopt, gettoken saves the value of a token in s and returns its type. The type of token is used in the switch case statement to decide which operation to do next.

  • The modulus operator % (indicated in exercise 4-3) is added in the switch case statement the same way as the rest of operators.

  • The commands of exercise 4-4 and the math functionalities of exercise 4-5 are added using the different types returned by gettoken: SIN, POW, EXP, DUP… wich are defined in tokenizer.h. This could have been done in another way if we could use pointers to functions, making the switch case much shorter. Exercises with pointers are solved in Chapter 5.

  • The stack is always visible, we do not need to pop an element to see its value and \n no longer removes an item from the stack, it needs to be done explicitly with del command.

  • To add the variable functionality from exercise 4-6 it would have been best to allow the stack to hold variables a-z aside from doubles values. However without using unions or structs from Chapter 6 the implementation would have been messy. What we did instead is make variables work in a simple way: when we enter a variable for the first time it saves the previous number, the next time we use the same variable it evaluates to the number saved. The list of saved variables is also visible while using the calculator.

tokenizer.h

#define ERR '0'
#define VAR '1'
#define NUM '2' 
#define POW '3'
#define EXP '4'
#define SIN '5'
#define SWP '6'
#define DUP '7'
#define DEL '8'
#define CLR '9'

int gettoken(char s[], int n);

void printstack(void);

tokenizer.c

#include "tokenizer.h"
#include "myio.h"
#include <stdio.h>
#include <ctype.h>

int isnumber(char s[]);
int ismath(char s[], char op[]);
int isvar(char s[]);

/*
* store a word in buffer s, indicating n as its maximum size
* trailing blanks are removed.
* a newline is considered a word of length 1, independently if it is colliding or now with another word.
* return the number of character readed 
* return 0 if EOF before any word or newline is encountered 
* return -1 if buffer s is not long enough to hold the word
*/
int getword(char s[], unsigned n);

int gettoken(char s[], int n)
{
    /* get next word */
    if (getword(s, n) == -1){
        return -1;
    }

    /* check its type: digit, math, variable or operator */
    if (isnumber(s)){
        return NUM;
    }else if (isvar(s)){
        return VAR;
    }else if (ismath(s, "pow")){
        return POW;
    }else if (ismath(s, "exp")){
        return EXP;
    }else if (ismath(s, "sin")){
        return SIN;
    }else if (ismath(s, "swap")){
        return SWP;
    }else if (ismath(s, "dup")){
        return DUP;
    }else if (ismath(s, "del")){
        return DEL;
    }else if (ismath(s, "clear")){
        return CLR;
    }else if (isvar(s)){
        return VAR;
    }
    return s[0];
}

int getword(char s[], unsigned n)
{
    int c, i;

    /* remove trailing blank lines */
    i = 0;
    while(isblank(c = getch()));
    if (c != EOF){
        s[i++] = c;
    }

    /* return if '\n' */
    if (c == '\n'){
        s[i] = '\0';
        return 1;
    }

    /* read every character until a blank or newline */
    while(i < n && (c = getch()) != EOF && !isblank(c) && c != '\n'){
        s[i++] = c;
    }

    /* error if n is not long enough - we do not try to recover */
    if (i >= n){
        return -1;
    }

    /* ungetch last character and return */
    s[i] = '\0';
    if (ungetch(c) == -1){
        return -1;
    }
    return i;
}

/* return 1 if s represent a number or 0 if not */
int isnumber(char s[])
{
    int i;
    /* get sign */
    i = 0;
    if ((s[0] == '+' || s[0] == '-') && s[1] != '\0'){
        ++i;
    }
    /* get all digits including '.' */
    while(isdigit(s[i])){
        ++i;
    }
    if (s[i] == '.'){
        ++i;
    }
    while(isdigit(s[i])){
        ++i;
    }
    /* check and return */
    if (i > 0 && s[i] == '\0'){
        return 1;
    }
    return 0;
}

int ismath(char s[], char op[])
{
    int i;
    for (i = 0 ; s[i] == op[i] && s[i] != '\0' ; ++i);
    if (s[i] == op[i] && s[i] == '\0'){
        return 1;
    }
    return 0;
}

int isvar(char s[])
{
    if (s[0] >= 'a' && s[0] <= 'z' && s[1] == '\0'){
        return 1;
    }
    return 0;
}

  • getopt functionality is refactored in different functions. As we have said gettoken is the interface; a safe function that saves a token in s and returns its value. getword is used to retrieve a word from the stdin (a modified version of Exercise 1-16) and isnumber, ismath and isvar are used to determine its type. All the possible types are defined in tokenizer.h for other files to use.

  • Notice that in the header, we only includes the functions that are intended to be used externally by other files. It does not include getword, isnumber, ismath and isvar since those are intended for internal use only.

stack.h

/* return the number on success and NAN on error */
double pop(void);
double peek(void);

/* return 0 on success and -1 on error */
int push(double x);
int swap(void);
int dup(void);

void clearstack(void);
void printstack(void);


stack.c

#include "stack.h"
#include <stdio.h>
#include <math.h>

#define MAXSTACK 16

double stack[MAXSTACK];
int rsp = 0; /* next free position of the stack */

double pop(void)
{
    if (rsp == 0){
        return NAN;
    }
    return stack[--rsp];
}

int push(double x)
{
    if (rsp >= MAXSTACK){
        return -1;
    }
    stack[rsp++] = x;
    return 0;
}

void clearstack(void)
{
    rsp = 0;
}

double peek(void)
{
    if (rsp == 0){
        return NAN;
    }
    return stack[rsp];
}

int swap(void)
{
    if (rsp < 2){
        return -1;
    }
    double tmp;
    tmp = stack[rsp-2];
    stack[rsp-2] = stack[rsp-1];
    stack[rsp-1] = tmp;
    return 0;
}

int dup(void)
{
    if (rsp < 1 || rsp + 1 >= MAXSTACK ){
        return -1;
    }
    double tmp = stack[rsp-1];
    stack[rsp++] = tmp;
    return 0;
}

void printstack(void)
{
    int i;
    for(i = 0 ; i < rsp ; ++i){
        printf("%d: %f\n", rsp-i-1, stack[i]);
    }
}
  • Additional functions has been added to the stack module to implement the additional functionality that the exercises required. An argument could be made about implementing duplicate and swap logic in main instead of here.

myio.h

int getch(void);

/* return 0 on success and -1 on error */
int ungetch(int c);

/* push s string into the input, return 0 on success and -1 on error */
int ungets(char s[]);

myio.c

#include "myio.h"
#include <stdio.h>
#include <ctype.h>

#define BUFSIZE 16

char buff[BUFSIZE];
int ibuf = 0;   /* next free position in buff */

int getch(void) 
{
    return (ibuf > 0) ? buff[--ibuf] : getchar();
}

int ungetch(int c) 
{
    if (ibuf >= BUFSIZE || c == EOF) {
        return -1;
    }
    buff[ibuf++] = c;
    return 0;
}


/* push s string into the input, return 0 on success and -1 on error */
int ungets(char s[])
{
    /* check if there is space*/
    int i, len;
    for (len = 0; s[len] != 0 ; ++i);
    if (len > BUFSIZE - ibuf){
        return -1;
    }

    /* push s in the correct order , ungetch should not fail */
    for (i = len -1 ; i >= 0 ; --i){
        if (ungetch(s[i]) == -1){
            return -1;
        }
    }
    return 0;
}
  • ungets routine is implemented in myio module. It just uses ungetch to implement its functionality, it does not touch buff directly.

variables.h

/* always call before using the module*/
void initvar(void);

/* get the value of variable var or NAN if it has not been used yet */
double getvar(char var);

/* set the value of variable var to x */
void setvar(char var, double x);

/* return 1 if the variable var has value or 0 if it has not been used yet */
int hasvalue(char var);

void printvar(void);

variables.c

#include "variables.h"
#include <stdio.h>
#include <math.h>

#define VARSIZE ('z' - 'a' + 1)

double vars[VARSIZE];
    
/* initialize variables values */
void initvar(void)
{
    int i;
    for (i = 0 ; i < VARSIZE ; ++i){
        vars[i] = NAN;
    }
}


double getvar(char var)
{
    return vars[var - 'a'];
}

void setvar(char var, double x)
{
    vars[var - 'a'] = x;
}

int hasvalue(char var)
{
    return !isnan(vars[var - 'a']);
}

void printvar(void)
{
    double v;
    int somevar;
    int i;

    somevar=0;
    printf("(");
    for (i = 0 ; i < VARSIZE ; ++i){
        v = vars[i];
        if (!isnan(v)){
            somevar = 1;
            printf("%c=%.1f, ", 'a' + i, v);
        }
    }
    if (somevar){
        printf("\b\b)\n");
    }else{
        printf("\b");
    }
}
  • We make another module (variables.h and variables.c) to implement variable evaluation logic. It is used directly by main.c.

Compilation and run:

$ gcc main.c variables.c tokenizer.c myio.c stack.c -lm
$ ./a.out
12 34 -22
2: 12.000000
1: 34.000000
0: -22.000000
> 2 2 +
3: 12.000000
2: 34.000000
1: -22.000000
0: 4.000000
> 3 -
3: 12.000000
2: 34.000000
1: -22.000000
0: 1.000000
> +
2: 12.000000
1: 34.000000
0: -21.000000
> dup
3: 12.000000
2: 34.000000
1: -21.000000
0: -21.000000
> exp
3: 12.000000
2: 34.000000
1: -21.000000
0: 0.000000
> del
2: 12.000000
1: 34.000000
0: -21.000000
> a
(a=-21.0)
1: 12.000000
0: 34.000000
> b
(a=-21.0, b=34.0)
0: 12.000000
> a b +
(a=-21.0, b=34.0)
1: 12.000000
0: 13.000000
> b pow
(a=-21.0, b=34.0)
1: 12.000000
0: 74829695578286079398588608906795155456.000000
> swp
error: Invalid input 'swp'
> swap
(a=-21.0, b=34.0)
1: 74829695578286079398588608906795155456.000000
0: 12.000000
> clear
(a=-21.0, b=34.0)
>

Exercise 4-8

Same as Exercises 4-3, 4-4, 4-5, 4-6 but with the following modifications to myio.h and myio.c:

myio.h

int getch(void);

/* return 0 on success and -1 on error */
int ungetch(int c);

myio.c

#include "myio.h"
#include <stdio.h>
#include <ctype.h>

#define BUFSIZE 16

char buffchar;
int ibuf = 0;   /* 0 not saved and 1 saved */

int getch(void) 
{
    if(ibuf){
        ibuf = 0;
        return buffchar;
    }
    return getchar();
}

int ungetch(int c) 
{
    if (ibuf || c == EOF) {
        return -1;
    }
    buffchar = c;
    ibuf = 1;
    return 0;
}

Notes:

  • There is no longer a buffer array, just one character buffer. ibuf no longer represent the position in the buffer, it only indicates if there is a character saved in the buffer or not.

  • getch and ungetch are modified to work with the new versions of buffchar and ibuf.

  • ungets get removed since it depended on having a buffer array (it was not used anyways).

Exercise 4-9

Same as Exercise 4-8 but modifying myio.c:

myio.c

#include "myio.h"
#include <stdio.h>
#include <ctype.h>

#define BUFSIZE 16

int buffchar;
int ibuf = 0;   /* 0 not saved and 1 saved */

int getch(void) 
{
    if(ibuf){
        ibuf = 0;
        return buffchar;
    }
    return getchar();
}

int ungetch(int c) 
{
    if (ibuf) {
        return -1;
    }
    buffchar = c;
    ibuf = 1;
    return 0;
}

Notes:

  • We just changed the type of buffchar from int to char, this way it can hold EOF values aside from characters.

  • Notice that ungetch no longer return error when trying to push EOF.

Exercise 4-10

Same as Exercise 4-9 but modifying myio.c:

myio.c

#include "myio.h"
#include <stdio.h>
#include <ctype.h>

unsigned long nb = 0;   
char *buff = NULL;
int len = 0; /* number of character readed by getline */
int pos = 0; /* current buffer position */

/* return 0 success and -1 on error */
int fillbuff(void)
{
    if ((len = getline(&buff, &nb, stdin)) < 0){
        return -1;
    }
    pos = 0;
    return 0;
}

int getch(void) 
{
    /* fill buffer if it is empty */
    if (len - pos == 0){
        if(fillbuff() == -1){
            return -1;
        }
    }
    return buff[pos++];
}

/* push s string into the input, return 0 on success and -1 on error */
int ungetch(int c) 
{
    if (pos == 0) {
        return -1;
    }
    buff[--pos] = c;
    return 0;
}

Notes:

  • Until now, we were using getchar from stdlib to read from the standard input. This exercise consist on organizing the code to use getline instead of getchar for reading from the standard input. The only functions that depends on getchar are getch and ungetch and, instead of getting rid of them and refactoring the whole program, we just make them use getline instead.

Exercise 4-11

Same as Exercises 4-3, 4-4, 4-5, 4-6 but modifying getword from tokenizer.c and removing myio.h and myio.c:

tokenizer.c

#include "tokenizer.h"
#include "myio.h"
#include <stdio.h>
#include <ctype.h>

int isnumber(char s[]);
int ismath(char s[], char op[]);
int isvar(char s[]);

/*
* store a word in buffer s, indicating n as its maximum size
* trailing blanks are removed.
* a newline is considered a word of length 1, independently if it is colliding or now with another word.
* return the number of character readed 
* return 0 if EOF before any word or newline is encountered 
* return -1 if buffer s is not long enough to hold the word
*/
int getword(char s[], unsigned n);

int gettoken(char s[], int n)
{
    /* get next word */
    if (getword(s, n) == -1){
        return -1;
    }

    /* check its type: digit, math, variable or operator */
    if (isnumber(s)){
        return NUM;
    }else if (isvar(s)){
        return VAR;
    }else if (ismath(s, "pow")){
        return POW;
    }else if (ismath(s, "exp")){
        return EXP;
    }else if (ismath(s, "sin")){
        return SIN;
    }else if (ismath(s, "swap")){
        return SWP;
    }else if (ismath(s, "dup")){
        return DUP;
    }else if (ismath(s, "del")){
        return DEL;
    }else if (ismath(s, "clear")){
        return CLR;
    }else if (isvar(s)){
        return VAR;
    }
    return s[0];
}

int getword(char s[], unsigned n)
{
    int c, i;

    /* remove trailing blank lines */
    i = 0;
    while(isblank(c = getch()));
    if (c != EOF){
        s[i++] = c;
    }

    /* return if '\n' */
    if (c == '\n'){
        s[i] = '\0';
        return 1;
    }

    /* read every character until a blank or newline */
    while(i < n && (c = getch()) != EOF && !isblank(c) && c != '\n'){
        s[i++] = c;
    }

    /* error if n is not long enough - we do not try to recover */
    if (i >= n){
        return -1;
    }

    /* ungetch last character and return */
    s[i] = '\0';
    if (ungetch(c) == -1){
        return -1;
    }
    return i;
}

/* return 1 if s represent a number or 0 if not */
int isnumber(char s[])
{
    int i;
    /* get sign */
    i = 0;
    if ((s[0] == '+' || s[0] == '-') && s[1] != '\0'){
        ++i;
    }
    /* get all digits including '.' */
    while(isdigit(s[i])){
        ++i;
    }
    if (s[i] == '.'){
        ++i;
    }
    while(isdigit(s[i])){
        ++i;
    }
    /* check and return */
    if (i > 0 && s[i] == '\0'){
        return 1;
    }
    return 0;
}

int ismath(char s[], char op[])
{
    int i;
    for (i = 0 ; s[i] == op[i] && s[i] != '\0' ; ++i);
    if (s[i] == op[i] && s[i] == '\0'){
        return 1;
    }
    return 0;
}

int isvar(char s[])
{
    if (s[0] >= 'a' && s[0] <= 'z' && s[1] == '\0'){
        return 1;
    }
    return 0;
}

Notes:
  • remember that * getch and ungetch were just wrappers around getchar (or getline) from the standard library to implememt the “unget character” functionality (which the standard library already have btw). Since we do not need that functionality anymore, we can get rid of them and of the whole myio module (myio.h and myio.c).

Exercise 4-12

main.c

#include <stdio.h>

#define CINTLEN 20

int itoa(char s[], int n);

int main()
{
    char s[CINTLEN];
    int n;

    while (scanf("%d", &n) == 1){
        itoa(s, n);
        printf("%s\n", s);
    }
    return 0;
}

int itoa_rec(char s[], unsigned n);

int itoa(char s[], int n)
{
    /* handle negative numbers */
    unsigned un;
    un = (unsigned) n;
    if (n < 0){
        un = ~un + 1;
        s[0] = '-';
        ++s;
    }

    /* recursive logic */
    int total_digits;
    total_digits = itoa_rec(s, un);

    /* finish s with null character '\0' */
    s[total_digits] = '\0';
}

/* 
* convert a integert n into a string s 
* (it only works for positive numbers and it does not add '\0' to end)
* it returns the number of digits of n 
*/
int itoa_rec(char s[], unsigned n)
{
    int n_digits;

    /* case base */
    if (n == 0){
        return 0;
    }
    /* recursive case */    
    n_digits = itoa_rec(s, n/10) + 1;
    s[n_digits-1] = n % 10 + '0';
    if (n < 10){
        s[n_digits] = '\0';
    }
    return n_digits;
}

Compilation and run:

$ gcc main.c
$ ./a.out
1234
1234
-1234
-1234

Notes:

  • Refer to Exercise 3-4 to understand why we use bitwise operators to handle negative numbers and to understand why we dont need to implement buffer overflow control even when CINTLEN is just 20.

Exercise 4-13

main.c

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

void reverse(char s[]);

int main()
{

    char *s;
    int len;
    long unsigned n;

    s = NULL;   
    n = 0;
    while((len = getline(&s, &n, stdin)) > 0){
        reverse(s);
        printf("%s\n", s);
    }
    free(s);
    return 0;
}

void reverse_rec(char s[], int start, int end);

void reverse(char s[])
{
    int len = strlen(s);
    if (len > 0 && s[len - 1] == '\n'){
        s[--len] = '\0';
    }
    reverse_rec(s, 0, strlen(s)-1);
}

void reverse_rec(char s[], int start, int end)
{
    // base case
    if (start >= end)
        return;
    // recursion
    char tmp;
    tmp = s[start];
    s[start] = s[end];
    s[end] = tmp;
    reverse_rec(s, ++start, --end);
}

Compilation and run:

$ gcc main.c
$ ./a.out
Hello!
!olleH
Is this working fine??
??enif gnikrow siht sI

Notes:

  • We used getline from standard library to read lines from input, see notes on Exercise 1-17 to remember its usage.

Exercise 4-14

main.c

#include <stdio.h>

#define swap(t, x, y)   {   t temp = x; \
                            x = y;      \
                            y = temp;   \
                        }
int main()
{
    int x;
    int y;

    while(scanf("%d %d", &x, &y)){
        swap(int, x, y);
        printf("%d %d\n", x, y);

    }

    return 0;
}

Compilation and run:

$ gcc main.c
$ ./a.out
1 2
2 1
123 -44
-44 123