Problems 4
  1. Theory
    1. Will these functions leak memory?
      void stat(){
      	double a[500];
      }
      
      void vla(size_t n){
      	double a[n];
      }
      
      void mal(){
      	double* a=(double*)malloc(500*sizeof(double));
      }
      
      void maf(){
      	double* a=(double*)malloc(500*sizeof(double));
      	free(a);
      }
      
      double* mar(){
      	double* a=(double*)malloc(500*sizeof(double));
      	return a;
      }
      
    2. Which lines, if any, of the following program will lead to compilation error?
      struct vector {double x,y,z;};
      struct vector v = {1,2,3};
      struct vector x = {1,2,3};
      struct vector a = [1,2,3];
      struct vector u = {.x=1,.y=2,.z=3};
      struct vector w = {.z=3,.y=2,.x=1};
      vector y;
      typedef struct vector vector;
      vector z;
      
    3. Which of the following Bash commands creates a list of '.c'-files in the current directory? Hint: Redirecting to and from the standard file handles.
      ls *.c > cfiles.txt
      ls *.c 1> cfiles.txt
      ls *.c 2> cfiles.txt
      ls *.c &> cfiles.txt
      rm -f cfiles.txt; for i in *.c; do echo $i >> cfiles.txt; done
      
    4. Where does the following main function get its parameter from?
      int main(int argc, char* argv[]) { /* do stuff */ }
      
    5. How can you convert a parameter of the main function into double or int number?
    6. What will the following program print?
      #include<stdio.h>
      #include<stdlib.h>
      double* foo(){ static double a[]={0,0,0}; return a; }
      int main(){
        double* a=foo(); a[2]=1;
        double* b=foo(); b[2]=2;
        printf("a[2] = %g\n",a[2]);
      return EXIT_SUCCESS;}
      
    7. What will the following program print?
      #include<stdio.h>
      #include<stdlib.h>
      double* foo(){ double* a=(double*)malloc(3*sizeof(double)); return a; }
      int main(){
        double* a=foo(); a[2]=1;
        double* b=foo(); b[2]=2;
        printf("a[2] = %g\n",a[2]);
        free(a);a=NULL;
        free(b);b=NULL;
      return EXIT_SUCCESS;}
      
    8. Can a C-structure contain a function? A pointer to a function?
    9. Which of the following lines is the correct declaration and why?
      struct f { int n; double *f(double); };
      struct g { int n; double (*f)(double); };
      
    10. Which of the two declarations is valid and why?
      #include<math.h>
      double (*f)(double) = sin;
      double (*f)(double) = &sin;
      
    11. With "f" from the (valid) declaration above, which of the following statements is valid and why?
      double y = f(1);
      double y = (*f)(1);
      
    12. What is the return value of the malloc function from stdlib.h?
  2. Practice

    1. Consider an implementation of n-dimensional vectors using the structure

      typedef struct {int size; double* data;} nvector;

      1. Implement the following set of functions to deal with these vectors:

        nvector* nvector_alloc       (int n);                           /* allocates memory for size-n vector */
        void     nvector_free        (nvector* v);                      /* frees memory */
        void     nvector_set         (nvector* v, int i, double value); /* v_i ← value */;
        double   nvector_get         (nvector* v, int i);               /* returns v_i */
        void     nvector_set_zero    (nvector* v);                      /* all elements ← 0 */
        double   nvector_dot_product (nvector* u, nvector* v);          /* returns dot-product */
        void     nvector_add         (nvector* a, nvector* b);          /* a_i ← a_i + b_i */
        void     nvector_sub         (nvector* a, nvector* b);          /* a_i ← a_i - b_i */
        void     nvector_scale       (nvector* a, double x);            /* a_i ← x*a_i     */
        

        Implement range checking using <assert.h>.

        Hints:

        typedef struct {int size; double* data;} nvector;
        
        nvector* nvector_alloc(int n){
          nvector* v = (nvector*)malloc(sizeof(nvector));
          (*v).size = n;
          (*v).data = (double*)malloc(n*sizeof(double));
          if( v==NULL ) fprintf(stderr,"error in nvector_alloc\n");
          return v;
        }
        
        void nvector_free(nvector* v){ free(v->data); free(v); }
        
        void nvector_set(nvector* v, int i, double value){
          assert(0<=i && i<(*v).size);
          (*v).data[i]=value;
        }
        
        
        
        
      2. Implement a main function that tests your functions, for example,
        #include "nvector.h"
        #include <stdio.h>
        #include <stdlib.h>
        
        int main(){
          int n=5;
        
          printf("main: testing nvector_alloc ...\n");
          nvector* v = nvector_alloc(n);
          if(v==NULL) printf("test failed\n");
          else        printf("test passed\n");
        
          printf("main: testing nvector_set and nvector_get ...\n");
          int error=0;
          for(int i=0;i<n;i++){
            double value = (double)rand();
            nvector_set(v,i,value);
            double vi = nvector_get(v,i);
            if(vi != value) error=1;
          }
          if(error==1) printf("test failed\n");
          else         printf("test passed\n");
        
          nvector_free(v);
        
        return 0;
        }
        
        
        
        			
    2. Consider a representation of complex numbers as the structure typedef struct {double re,im;} komplex;

      1. Implement the following set of functions to deal with complex numbers:

        komplex komplex_add      (komplex a, komplex b);            /* returns a+b */
        komplex komplex_sub      (komplex a, komplex b);            /* returns a-b */
        komplex komplex_mul      (komplex a, komplex b);            /* returns a*b */
        komplex komplex_div      (komplex a, komplex b);            /* returns a/b */
        komplex komplex_set      (komplex* z, double x, double y);  /* z ← x+i*y */
        komplex komplex_conjugate(komplex z);            /* returns complex conjugate */
        komplex komplex_exp      (komplex z);            /* returns complex exponential function of the argument: you are only allowed to use real functions from math.h here ;) */
        void    komplex_print    (komplex z); /* prints the complex number */
        int     komplex_equal    (komplex a, komplex b); /* returns 1 if equal, 0 otherwise */
        
        Hints:
        typedef struct {double re,im;} komplex;
        
        komplex komplex_add(komplex a, komplex b){
        	double x = a.re + b.re, y = a.im + b.im;
        	komplex result = {.im = y, .re = x}; /* ;) */
        	return result;
        	}
        
        int komplex_equal(komplex a, komplex b){
        	if( a.re==b.re && a.im==b.im) return 1; else return 0;
        	}
        
        double komplex_abs(komplex z){
           double x=fabs(z.re), y=fabs(z.im);
           if(x==0 && y==0) return 0;
           if(x>y) {double t=y/x; return x*sqrt(1.0+t*t);}
           else    {double t=x/y; return y*sqrt(1.0+t*t);}
        }
        
        komplex komplex_div(komplex a, komplex b){
           if( fabs(b.im)<abs(b.re) )
              {
                 double e = b.im/b.re;
                 double f = b.re+b.im*e;
                 komplex result = {.re = (a.re+a.im*e)/f, .im = (a.im-a.re*e)/f};
                 return result;
              }
           else
              {
                 double e = b.re/b.im;
                 double f = b.im+b.re*e;
                 komplex result = {.re = (a.im+a.re*e)/f, .im = (-a.re+a.im*e)/f};
                 return result;
              }
           }
        ...
        
      2. Write a main program that tests you functions
        Hints:
        komplex a = {1,2}, b = {3,4}, r = {4,6};
        komplex c = komplex_add(a,b);
        if( komplex_equal(c,r) ) printf("test 'add' passed :) \n");
        else printf("test 'add' failed :( \n");