2

Normally I always compiled my C code like this: g++ program.c -o program.exe

But my college professor requires me to compile using:g++ -o -Wall -Wextra -Werror -pedantic -std=c++0x program.exe program.c

(Which is new for me).

So ... I run the command and get the following error:

eda.c: In function ‘int main()’:
eda.c:200: error: ISO C++ forbids variable-size array ‘v’
eda.c:207: error: ISO C++ forbids variable-size array ‘nfloat’
cc1plus: warnings being treated as errors
eda.c:215: warning: suggest a space before ‘;’ or explicit braces around empty body in         ‘while’ statement

And this is the code of my program:

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


typedef struct {
    float* data;
    int size;
} vector;


/* Metodos Básicos */
vector *create_vector(int n, float* comps){
    vector *newvect = (vector*)malloc(sizeof(*newvect));
    newvect->data = (float*)malloc(n*sizeof(float));
    memcpy(newvect->data, comps, sizeof(float) * n);
    newvect->size = n;
    return newvect;
}

void destroy_vector(vector* v){
    free(v->data);
    free(v);
}

void print(vector* v){
    int size = v->size, i;
    for (i = 0; i < size; ++i)
    {
        if(i == 0) printf("[%.1f,", v->data[i]);
        else if(i == (size-1)) printf("%.1f]\n", v->data[i]);
        else printf("%.1f,", v->data[i]);
    }
}

/* Metodos Intermedios */
float dotDiferentSizes(vector* v1, vector* v2, int smax, int smin){
    double product;
    int i;
    for(i = 0; i < smin; i++){
        product += (v1->data[i])*(v2->data[i]); // += means add to product
    }
    for(i = smin; i < smax; i++){
        product += (v1->data[i])*0; // += means add to product
    }
    return product;
}

float dot(vector* v1, vector* v2){
    int smax = (v1->size), smin;
    int v1size = smax;
    int v2size = (v2->size);
    float product = 0.0;
    if (v2->size > smax) {
        smax = v2->size; //max_size checking
        smin = v1->size; //min_size checking
    }
    else if (v2->size < smax){
            smin = v2->size;
    }
    else smin = smax;
    // compute
    if(smax == smin){
        int i;
        for(i = 0; i < smin; i++){
            product += (v1->data[i])*(v2->data[i]); // += means add to product
        }
    }
    else{
        if(v1size == smax){
            product = dotDiferentSizes(v1,v2,smax,smin); //v1>v2
        }
        if(v2size == smax){
            product = dotDiferentSizes(v2,v1,smax,smin); 
        }
    }
    return product;
}

float norm(vector* v){
    int size = v->size, i;
    float norm = 0.0;
    for(i= 0; i < size; i++){
        norm += (v->data[i])*(v->data[i]);
    }
    norm = sqrt( norm );
    return norm;
}

void normalize(vector* v){
    int size = v->size, i;
    float norma = 0.0;
    norma = norm(v);
    for(i= 0; i< size; i++){
        v->data[i] = v->data[i] / norma;
    }
    for (i = 0; i < size; ++i)
    {
        if(i == 0) printf("NORMALIZED VECTOR:[%.2f,", v->data[i]);
        else if(i == (size-1)) printf("%.2f]\n", v->data[i]);
        else printf("%.2f,", v->data[i]);
    }
}

/* Metodos Avanzados */
vector* add(vector* v1, vector* v2){
    vector *vadd;
    int v1size, v2size, i;
    v1size = v1->size;
    int size = v1size;
    v2size = v2->size;
    if(v2size > v1size) {
        size = v2size;
        vadd = create_vector(size, v2->data);
        for(i = 0; i < v1size; i++){
            vadd->data[i] += v1->data[i];
        }
    }
    else {
        vadd = create_vector(size, v1->data);
        for(i = 0; i < v1size; i++){
            vadd->data[i] += v2->data[i];
        }
    }
    return(vadd);
}

vector* sub(vector* v1, vector* v2){
    vector *vsub;
    int v1size, v2size, i;
    v1size = v1->size;
    int size = v1size;
    v2size = v2->size;
    if(v2size > v1size) {
        size = v2size;
        vsub = create_vector(size, v2->data);
        for(i = 0; i < v1size; i++){
            vsub->data[i] = v1->data[i] - vsub->data[i]; /* restamos siempre v1 - v2*/
        } /* en el bucle forzamos a restar v1 - v2, evitando el caso v2 - v1*/
        for(i = v1size; i < size; i++){
            vsub->data[i] = (v2->data[i])*(-1);
        }
    }
    else { /* v1size >= v2size */
        vsub = create_vector(size, v1->data);
        for(i = 0; i < v2size; i++){
            vsub->data[i] -= v2->data[i];
        }
    }
    return(vsub);
}

void incr(vector* source, vector* other){
    int smax, i, ssize = source->size, osize = other->size;
    vector *vincr;
    if(ssize > osize) smax = ssize;
    else {
        if(ssize < osize) smax = osize;
        else smax = ssize;
    }
    vincr = add(source, other);
    if(ssize > osize){
        for(i = 0; i < smax; i++){
            source->data[i] = vincr->data[i];
        }
    }
    else{
        source->data = (float*)realloc(source->data, sizeof(float) * smax);
        source->size = smax;    
        for(i = 0; i < smax; i++){
            source->data[i] = vincr->data[i];
        }
    }
    print(source);
    free(vincr);
}

//NumsVector, funcion que nos devuelve el numero de "numeros" que hay en cada vector del .txt,
//es decir, los n floats por cada vector

int NumsVector(char *linea, ssize_t size){
    int numsvector = 1; //Inicializamos a 1 ya que no podemos suponer valor maximo segun enunciado, pero si minimo >= 1
    int n;
    for(n = 2; n<= size; n++){ //como ya suponemos que el primer valor despues del corchete es un numero y ya lo hemos contado, empezamos en 2
        if (linea[n] != '[' && linea[n] != ']'){
            if(linea[n] == 44){
                numsvector = numsvector + 1;
            }
        }
    }
    return numsvector;
}


int main(){
    int n, i;
    scanf("%d\n", &n);
    vector *v[n];
    for(i = 0; i<n; ++i) { 
        char *line = NULL;  //ponemos *line y len a valores 0 y null para que automaticamente getline nos haga el malloc y nos asigne el tamanyo
        size_t len = 0;
        ssize_t read; //en la variable read guardamos el valor de getline, contiene el numero de caracteres que tiene el string
        read = getline(&line,&len,stdin);
        int numsvector = NumsVector(line, read); 
        float nfloat[numsvector]; //sabemos el tamanyo del vector que hemos leido, creamos array de floats y lo llenamos de los floats
        //empieza el proceso para obtener los floats a partir de string de chars
        int j = 0;
        line[strlen(line) - 1] = ','; /* Replaces the end ] with a , */
        char *p = line + 1; /* creates a new pointer, pointing after the first [ in the original string */
        do
        {
            sscanf(p, "%f,", &nfloat[j]); /* grabs up to the next comma as a float */       
            while (*(p++) != ',') ; /* moves pointer forward to next comma */
        }
        while (++j < numsvector); /* stops when you've got the expected number */     
        v[i] = create_vector(numsvector, nfloat);//conseguimos almacenar el contenido del string en un vector del tipo float (nfloat)
        int aux;
        for(aux = 0; aux<numsvector; ++aux){ 
            printf("V[%d]->data[%d] = : %.1f\n", i, aux, v[i]->data[aux]); //test de que la memoria se almacena bien, luego se borra
        }
        free(line);
    }
}

These are the lines that give errors:

200: vector *v[n];
207: float nfloat[numsvector];
215: while (*(p++) != ',') ; //Now I think works fine with the extra space..

please could someone help me compile the file?

zubergu
  • 3,646
  • 3
  • 25
  • 38
Cheknov
  • 1,892
  • 6
  • 28
  • 55
  • You sure you want `C++` for this? This code looks like `C` to me. – crashmstr Oct 16 '13 at 19:34
  • 1
    If this is a C++ program, don't use `malloc` and `free`. Try `new` and `delete` instead. – Sinkingpoint Oct 16 '13 at 19:36
  • @crashmstr I can only use C – Cheknov Oct 16 '13 at 19:39
  • 4
    @Gerard So why is this tagged C++? Why are you using g++? If you can use only C, then write C code and compile it as C code. – jamesdlin Oct 16 '13 at 19:40
  • vector is a common data structure (i.e. std::vector), I would recommend you rename your struct by a different name. – jmstoker Oct 16 '13 at 19:41
  • @jmstoker This is C code so `vector` is perfectly fine. It just shouldn't be tagged c++ nor compiled with g++.. – Voo Oct 16 '13 at 19:41
  • 1
    @Voo It is the desire of my teacher, we can only use g+ + and c language – Cheknov Oct 16 '13 at 19:44
  • @Gerard I think you need a full explanation from this teacher about *why* they have this restriction, and what you will learn from this restriction. – crashmstr Oct 16 '13 at 19:48
  • @crashmstr Nothing, I think he does just to annoy... – Cheknov Oct 16 '13 at 19:48
  • @Voo I understand that it can be used, but it can cause confusion which has already manifested itself by all of the std::vector answers. – jmstoker Oct 16 '13 at 19:51
  • 3
    @Gerard: it's worse than annoying; C and C++ have different semantics in some fundamental areas (size and types of character constants, types of c-style strings, treatment of `void` pointers, etc.). If he's demanding you compile *C code* with a *C++ compiler*, then he's setting you up for problems later on. There's no good justification for it. – John Bode Oct 16 '13 at 20:17

3 Answers3

5

The problem is that the feature your are using(Variable Length Arrays or VLA) is a C99 feature and is not part of C++ standard but gcc supports it as an extension, -pedantic will force gcc to warn you when you are using extensions and -Werror will make warnings errors which will effectively prevent you from using extensions.

One option if you are are able to use C++ would be to use std::vector. Another option would be to use dynamic allocation via new or malloc depending on which you are allowed to use.

It is a bit odd that it seems like you have to program in C but use C++ compiler, I would expect at least that you could use -x c to make g++ to act as a C compiler. Here is an article that covers the Compatibility of C and C++, you should also read Keith's comments as well.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • @ShafikYaghmour My teacher forced us to use the g++ compiler and C language :( – Cheknov Oct 16 '13 at 19:37
  • 5
    @Gerard: Your teacher is making a serious mistake. g++ is not a C compiler, it's a C++ compiler, and C is most definitely *not* a proper subset of C++. The main problem is that C++ forces a cast on the result of `malloc`, which is legal but poor style in C (`int *p = malloc(sizeof *p);` is valid C, but C++ doesn't do the implicit conversion). If that's what you're stuck with, make sure your code compiles cleanly with *both* `g++ -Wall -Wextra -Werror -pedantic -std=c++0x` *and* `gcc -Wall -Wextra `Werror -pedantic -std=c99`. – Keith Thompson Oct 16 '13 at 19:43
  • @crashmstr If I could I would :) – Cheknov Oct 16 '13 at 19:45
  • @KeithThompson I would have added this [previous thread](http://stackoverflow.com/questions/861517/what-issues-can-i-expect-compiling-c-code-with-a-c-compiler?lq=1) to my answer as well but alas the article the top answers link to seems to not work. – Shafik Yaghmour Oct 16 '13 at 19:55
2

Normally I always compiled my C code like this: g++ program.c -o program.exe

That's incorrect. g++ is a C++ compiler, not a C compiler. (I know, you can specify -x c to force the language, but why would you do that when you have a C compiler as well?)

C code should be compiled with a C compiler. C++ code should be compiled with a C++ compiler. Any other combination is erroneous.

If you are required to write C++ code, then write C++ code. In C++, you can't have C99-style variable-length arrays. You will need to use std::vector instead. Like this:

std::vector<some_type> theVector(initial_size);
  • 7
    @Gerard What kind of brain-dead school are you attending? Using C with a C++ compiler is wrong. Just like compiling C++ code with a C compiler. You simply **can't do that.** –  Oct 16 '13 at 19:40
1

200: vector *v[n]; can be fixed by initializing the vector:

vector* v = new vector[n];

207: float nfloat[numsvector]; can be fixed by dynamically allocating the array:

float* nfloat = new float[numsvector]

I believe these are the corresponding C memory allocations:

vector* v = malloc(n * sizeof(vector));

float* nfloat = malloc(numsvector * sizeof(float));
  • 2
    Caution, his code declares a struct by the same name, vector. – jmstoker Oct 16 '13 at 19:39
  • The question is about building a `vector` in `C`, not using `std::vector`. – crashmstr Oct 16 '13 at 19:41
  • I've edited the code so it doesn't use std::vector. Only the memory allocation needs to be in C now. –  Oct 16 '13 at 19:45
  • @DaanKolthof the memory allocation for `nfloat` works, many thanks!, but for `v` I think is incorrect, I tried: `vector *v[n] = (vector*)malloc(sizeof(*v[n]));` And I get on screen: `iMac-de-Gerard:Desktop Gera$ g++ -Wall -Wextra -Werror -pedantic -o eda.exe eda.c eda.c: In function ‘int main()’: eda.c:225: error: ISO C++ forbids variable-size array ‘v’ eda.c:225: error: variable-sized object ‘v’ may not be initialized` – Cheknov Oct 16 '13 at 20:06
  • @H2CO3 Explain please. –  Oct 16 '13 at 20:18
  • 1
    In C you wouldn't cast the return of `malloc`, this is frowned upon. This is one of the differences that make compiling C code with a C++ a completely stupid idea. – Jens Gustedt Oct 16 '13 at 20:26
  • Isn't that leaking storage? – Hot Licks Oct 16 '13 at 20:58
  • Is `v` supposed to be an array of `vector` or an array of pointers to `vector`? In the original code, it was declared as `vector *v[n]`, which implies the latter. That would look more like `vector **v = (vector *)malloc(sizeof *v * n)` (casting the result since the OP is required to compile his C code with g++, which is *wrong*, but his professor isn't here to bitch at). – John Bode Oct 16 '13 at 21:09
  • @JohnBode you're right, `v` is an array of pointers to `vector`, I'll try your code, thank you very much! – Cheknov Oct 17 '13 at 10:00