0

I am trying to make a generic vector in c. Here is my header file (file called 'vector.h'):

#ifndef _vector_
#define _vector_
typedef struct{
    void * elems;
    int elem_size;
    int log_len;
    int alloc_len;
    int init_alloc;
}vector;

void vector_new(vector *v, int elem_size, int init_alloc);

void vector_dispose(vector * v);

int vector_length(const vector *v);

void *vector_nth(const vector *v, int position);

void vector_insert(vector *v, const void *elem_addr, int position);

void vector_append(vector *v, const void *elem_addr);

void vector_replace(vector *v, const void *elem_addr, int position);

void vector_delete(vector *v, int position);
#endif

Here is the source implementation of that header file (called 'vector.c')

#include "vector.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

void grow(vector *v){
    v-> alloc_len += v->init_alloc;
    v->elems =  realloc(v->elems, v->elem_size * v->alloc_len);
}

void vector_new(vector *v, int elem_size, int init_alloc){
    assert(elem_size > 0);
    assert(init_alloc > 0);
    assert(v != NULL);

    v->alloc_len = init_alloc;
    v->init_alloc = init_alloc;
    v->log_len = 0;
    v->elem_size = elem_size;
    v->elems = malloc(v->elem_size * v->alloc_len);
}

void vector_dispose(vector * v){
    assert(v != NULL);

    free(v->elems);
}

int vector_length(const vector *v){
    assert(v != NULL);

    return v->log_len;
}

void *vector_nth(const vector *v, int position){
    assert(v != NULL);
    assert(position >= 0);
    assert(position < v->log_len);

    return (char *)v->elems + v->elem_size * position;
}

void vector_insert(vector *v, const void *elem_addr, int position){
    assert(v != NULL);
    assert(position >= 0);
    assert(position <= v->log_len);

    if(v->log_len == v->alloc_len)
        grow(v);

    void * destination = (char *)v->elems + (position + 1) * v->elem_size;
    void * source = (char *)v->elems + position * v->elem_size;
    int move_size = (v->log_len - position) * v->elem_size;

    memmove(destination, source, move_size);
    source = memcpy(source, elem_addr, v->elem_size);
    v->log_len ++;
}

void vector_append(vector *v, const void *elem_addr){
    assert(v != NULL);
    assert(elem_addr != NULL);

    if(v->log_len == v->alloc_len)
        grow(v);

    void * destination = (char *)v->elems + v->elem_size * v->log_len;
    memcpy(destination, elem_addr, v->elem_size);
    v->log_len ++;
}

void vector_replace(vector *v, const void *elem_addr, int position){
    assert(v != NULL);
    assert(elem_addr != NULL);
    assert(position >= 0);
    assert(position < v->log_len);

    void * destination = (char *)v->elems + position * v->elem_size;
    memcpy(destination, elem_addr, v->elem_size);
}


void vector_delete(vector *v, int position){
    assert(v != NULL);
    assert(position >= 0);
    assert(position < v->log_len);

    void * destination = (char *)v->elems + position * v->elem_size;
    void * source = (char *)v->elems + (position + 1) * v->elem_size;
    int move_size = (v->log_len - position + 1) * v->elem_size;
    memmove(destination, source, move_size);
    v->log_len --;
}

As I have knowledge, now when I include "vector.h" in some other file (called 'test.c') it should work fine so I have the following code in separate file:

#include "vector.h"
#include <stdio.h>
#include <stdlib.h>

void main(){
    printf("########## CREATING VECTOR ########## \n");
    vector v;
    vector_new(&v, 4, 15);

    printf("########## STARTING APPEND ########## \n");
    printf("Size Now Is: %d\n", vector_length(&v));

    for(int i = 0; i < 10; i++){
        int random_number = rand() % 50;
        vector_append(&v, &random_number);
    }

    for(int i = 0; i < vector_length(&v); i++){
        printf("%dth Element Is: %d\n",i,*((int *)vector_nth(&v, i)));
    }

    printf("Size Now Is: %d\n", vector_length(&v));
    printf("########## STARTING REPLACE ########## \n");
    printf("Size Now Is: %d\n", vector_length(&v));

    int first = 1;
    int second = 2;
    vector_replace(&v, &first, 0);
    vector_replace(&v, &second, 1);

    for(int i = 0; i < vector_length(&v); i++){
        printf("%dth Element Is: %d\n",i,*((int *)vector_nth(&v, i)));
    }

    printf("Size Now Is: %d\n", vector_length(&v));
    printf("########## STARTING DELETE ########## \n");
    printf("Size Now Is: %d\n", vector_length(&v));

    vector_delete(&v, 3);
    vector_delete(&v, 4);
    vector_delete(&v, 5);

    for(int i = 0; i < vector_length(&v); i++){
        printf("%dth Element Is: %d\n",i,*((int *)vector_nth(&v, i)));
    }

    printf("Size Now Is: %d\n", vector_length(&v));
    printf("########## STARTING INSERT ########## \n");
    printf("Size Now Is: %d\n", vector_length(&v));

    int eight = 8;
    int nine = 9;
    int ten = 10;

    vector_insert(&v, &eight, 0);
    vector_insert(&v, &nine, 0);
    vector_insert(&v, &ten, 9);

    for(int i = 0; i < vector_length(&v); i++){
        printf("%dth Element Is: %d\n",i,*((int *)vector_nth(&v, i)));
    }

    vector_dispose(&v);
}

But instead it's giving the following error:

||=== Build file: "no target" in "no project" (compiler: unknown) ===| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_new'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_append'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_nth'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_replace'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_replace'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_nth'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_delete'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_delete'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_delete'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_nth'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_insert'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_insert'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_insert'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_nth'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference to vector_length'| C:\Users\George\Desktop\Random Files\C\test.o:test.c|| undefined reference tovector_dispose'| ||error: ld returned 1 exit status| ||=== Build failed: 27 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

But when I also include "vector.c" in this file, it works just fine. Can you suggest the possible reason ?

Banned
  • 43
  • 6
  • How do you build? Please show the command line or explain otherwise. Do you use somethign like `gcc onefileonly.c`? – Yunnosch Aug 26 '17 at 20:17
  • 2
    You have to link both `test.o` and `vector.o` (e.g. `gcc -o test test.o vector.o`) — or link `test.o` and the library containing your `vector.o` (e.g. `gcc -o test test.o -lvector`, assuming you have created such a library). Including a header tells the compiler about what funcionality is available elsewhere; it doesn't tell the linker where to find the functionality. When you include the `.c` file, the functions are included verbatim in the translation unit, but that's a technique reserved for special situations, and this isn't _that_ special. This must be a duplicate of many other questions. – Jonathan Leffler Aug 26 '17 at 20:24
  • @Yunnosch I just build it with codeblocks IDE. – Banned Aug 26 '17 at 20:27
  • @JonathanLeffler I also thought "dup", but didn't find one. Since this indeed is often the answer (even if not here) I would appreciate a link, if you have one. – Yunnosch Aug 26 '17 at 20:29
  • 1
    @Yunnosch [one suggestion](https://stackoverflow.com/questions/18548157/c-header-files-and-compilation-linking). – Weather Vane Aug 26 '17 at 20:31
  • @Yunnosch: I'll go hunt one down; I should have one in my list of relevant questions. There may be something in the C tag wiki already. I periodically think about creating an omnibus question for linking errors analogous to the C++ Q&A [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/) A lot of what's there is relevant to C; some of it is not. – Jonathan Leffler Aug 26 '17 at 20:34
  • I'm coming to the conclusion that there isn't a _good_ duplicate from 2010 or earlier, which is a bit surprising. In theory, Documentation could have covered the problems, but I'm not sure I remember seeing a focussed item on the topic, and it was always rather hard to find topics in Documentation — one of the reasons it is closed down. (Documentation requires more structure than 'number of up-votes on the items'. And once you get to 60 topics, you need to be able to impose more hierarchy on the system. But that's probably preaching to the choir.) – Jonathan Leffler Aug 26 '17 at 21:21
  • I've created a chat room [C Undefined References](https://chat.stackoverflow.com/rooms/152916/c-undefined-references) specifically to discuss the creation of a definitive Q&A on 'undefined references' in C. Please join if you're interested. (@Yunnosch) – Jonathan Leffler Aug 26 '17 at 21:22
  • @WeatherVane: see note about [C Undefined References](https://chat.stackoverflow.com/rooms/152916/c-undefined-references) chat room. – Jonathan Leffler Aug 26 '17 at 21:23
  • If you're using Code::Blocks and the default setup with the bundled Mingw compiler, then I think you've goofed up your project somewhere. Notice the "no target", "no project", and "compiler: unknown" at the top. I think it's highly likely that you forgot to add your new source files to each target. When you click "File > New > File" and choose the file type, when it asks you to name the file, it also asks which targets to add the file into the build for. By default, none are checked. It's easy to blast past this and completely forget it, only to wind up with an error like this one. – SeanRamey Aug 27 '17 at 03:57

0 Answers0