2010-12-12 15 views
5

Có thể sao chép một mảng chung trong ANSI-C thuần túy không?ANSI-C tinh khiết: tạo mảng chung

Tôi có cấu trúc này chứa một mảng (cho nổi tại thời điểm này) và một số biến như kích thước và dung lượng cho đột biến trong mảng.

typedef struct _CustomArray 
{ 
    float* array; //the array in which the objects will be stored 
    int size; //the current size of the array 
    int capacity; //the max capacity of the array 
} CustomArray; 

tôi sử dụng này struct vì vậy tôi có thể làm cho một mảng trong C tinh khiết nơi tôi có thể thêm/gỡ bỏ các mục, tự động mở rộng kích thước mảng khi cần thiết vv tất cả những điều một mảng "chuẩn" không, ngoại trừ nó là chỉ được thực hiện trong C. Và bây giờ tôi muốn thực hiện điều này để khi bạn khởi tạo cấu trúc này, bạn có thể đặt kiểu dữ liệu của các phần tử cần giữ, tại thời điểm này, nó chỉ có khả năng lưu trữ kiểu dữ liệu float, nhưng tôi muốn làm cho nó có thể lưu trữ bất kỳ datatype/các cấu trúc khác. Nhưng tôi không biết điều này có thể xảy ra hay không.

Tại thời điểm này các chức năng để làm cho mảng này là:

CustomArray* CustomArray_Create(int initCapacity, /*type elementType*/) 
{ 
    CustomArray* customArray_ptr; //create pointer to point at the structure 
    float* internalArray = (float*)malloc(sizeof(float) * initCapacity); //create the internal array that holds the items 
    if(internalArray != NULL) 
    { 
     CustomArray customArray = { internalArray, 0, initCapacity }; //make the struct with the data 
     customArray_ptr = &customArray; //get the adress of the structure and assign it to the pointer 
     return customArray_ptr; //return the pointer 
    } 
    return NULL; 
} 

Có thể đưa ra một kiểu dữ liệu như tham số vì vậy tôi có thể malloc bộ nhớ cho datatype đó và quăng nó như datatype được đưa ra trong một mảng động ?

Cảm ơn trước,

Marnix van Rijswijk

+0

Đừng nghĩ trong Pure C bạn có thể chuyển loại dữ liệu theo cách đó. Nhìn vào các ngôn ngữ hỗ trợ danh sách mảng không đồng nhất, ví dụ C#, nó chỉ hoạt động đối với các kiểu dữ liệu không cơ bản, đó là Lớp và không phải trên int, float, vv .. Vì C không hướng đối tượng, rất khó có khả năng bạn sẽ có được cơ sở này. –

+2

không bắt đầu từ định danh với dấu gạch dưới: các tên như vậy được dành riêng cho việc triển khai (compiler + libc); sử dụng dấu gạch dưới và chữ hoa sau là gấp đôi-xấu: những tên này được đặt trước trong bất kỳ ngữ cảnh nào vì đó là những tính năng ngôn ngữ mới sử dụng (ví dụ '_Pragma',' _Complex', '_Bool', ...); một cách giải quyết dễ dàng là sử dụng dấu gạch dưới, cũng có vẻ đẹp với tiền tố dựa trên tiền tố – Christoph

+1

Có một số câu hỏi trên trang web liên quan đến cách có thể xây dựng hành vi hướng đối tượng trong c: [Object-Orientation in C] (http://stackoverflow.com/q/415452/2509) và [Bạn có thể viết mã hướng đối tượng trong C?] (http://stackoverflow.com/q/351733/2509) và các mã khác. Bạn có thể đạt được kết quả mong muốn của mình bằng cách sử dụng một cách khôn ngoan 'sizeof' và cơ chế con trỏ hàm được thảo luận trong các liên kết, nhưng nó sẽ có nhiều công việc hơn. Giao diện 'qsort' và' bsearch' là một sự thỏa hiệp. – dmckee

Trả lời

8

Mã của bạn có một vấn đề nghiêm trọng ... bạn đang trả lại địa chỉ của một biến địa phương (CustomArray) và khi hàm trả về mà biến được phá hủy, do đó bạn không thể tiếp tục sử dụng nó với con trỏ. Bạn phải malloc cũng cấu trúc đó để bộ nhớ sẽ vẫn có sẵn khi hàm trả về.

Về việc loại một tham số bạn có thể nhận được phần nào gần sử dụng các macro ... ví dụ với một cái gì đó như:

#include <stdlib.h> 
#define DefArray(type) \ 
typedef struct T_##type##Array {\ 
    type *array; \ 
    int size, capacity; \ 
} type##Array; \ 
static type##Array *type##ArrayCreate(int capacity)\ 
{\ 
    type##Array *s = malloc(sizeof(type##Array));\ 
    if (!s) return NULL;\ 
    s->array = malloc(sizeof(type) * capacity);\ 
    if (!s->array) { free(s); return NULL; }\ 
    s->size=0; s->capacity = capacity;\ 
    return s;\ 
} 

Sau đó, bạn có thể sử dụng nó theo cách này

#include "customarray.h" 
DefArray(float); 
DefArray(double); 

void foo() 
{ 
    floatArray *fa = floatArrayCreate(100); 
    ... 
} 

Lưu ý rằng bạn đã sử dụng các macro để xác định tất cả các chức năng tùy chỉnh của bạn. Cũng lưu ý rằng cách tiếp cận này sẽ lặp lại mã trong mỗi mô-đun (tôi muốn nói không phải là một vấn đề lớn nhưng nếu bạn không thể sử dụng C++ có lẽ nền tảng đích của bạn là khá nhỏ). Với cách tiếp cận phức tạp hơn một chút, bạn có thể tạo tệp .h và tệp .h riêng biệt để triển khai.

+0

damn tốt đẹp, tôi sẽ cố gắng này quá chắc chắn. cám ơn vì cái này. –

+0

nó hoạt động, và nó cũng cho tôi thấy một cách hoàn toàn mới để làm việc. tuyệt vời. –

+3

Hehe ... chào mừng bạn đến với thế giới của lập trình meta (viết mã viết mã). Bộ tiền xử lý C là một dạng siêu lập trình siêu yếu, máy móc mẫu C++ chỉ tốt hơn một chút. Đối với ma thuật thực sự bạn đã sử dụng các trình tạo bên ngoài (viết các trình tạo C/C++ ví dụ trong python/perl dễ dàng) hoặc chuyển sang các ngôn ngữ khác, nơi có khả năng lập trình meta chính xác (ví dụ: Lisp). – 6502

2

Boy, điều này thực sự có vẻ như một công việc cho C++.

Tôi nghĩ rằng gần nhất bạn có thể đến đây trong C là không vượt qua loại, mà là kích thước (sizeof (loại)).

Bạn có thể làm cho chức năng của mình trở nên chung chung hơn để nó có thể làm những gì cần làm nếu tất cả những gì nó biết là kích thước của từng mục trong mảng. Đây là cách các hàm như công cụ bsearch().

+0

hmm cảm ơn, tôi biết nhiều hơn một công việc của nó cho c + +. nhưng tôi đã tự hỏi nếu nó có thể. : [thật đáng buồn là không. –

+0

Có an toàn để đưa ra các giả định về kiểu dữ liệu chỉ bằng cách nhìn vào kích thước không? –

+0

Pháo thủ: Sẽ an toàn khi đưa ra giả định về lượng bộ nhớ mà mỗi mục sử dụng. Điều đó là đủ để phân bổ và di chuyển bộ nhớ. Vấn đề duy nhất là nếu kiểu dữ liệu là một con trỏ. Trong trường hợp đó, mục được trỏ đến cũng nên được sao chép. Nhưng đối với tất cả các loại cơ bản, cách tiếp cận này hoàn toàn hợp lệ. –

2

Một cách để đạt được điều này là sử dụng cái gọi là X-macros.

Here là một (có thể lỗi) thực hiện vectơ chung sử dụng kỹ thuật này.

Nó sau đó được sử dụng như

// defining generic parameters 
#define PREFIX tv 
#define ITEM token 
#define NAME token_vector 
#include "vector.h" 

... 
token_vector tv = tv_new(100); 
*(tv.front) = some_token; 
tv_push_back(&tv, other_token); 
0

Tôi đã rối tung xung quanh với lập trình chung trong C vài năm trước, chỉ vì nó.

Về cơ bản, tôi đã kết thúc khai thác bộ tiền xử lý. Tôi đoán tôi đã thành công nhẹ nhàng: Tôi đã thực hiện một số ký hiệu macro cho một số cấu trúc dữ liệu chung quan trọng nhất.

Điều tôi chắc chắn KHÔNG thực hiện (theo bất kỳ cách nào tự động ít nhất) được đệ quy chạy macro - tức là tạo mảng mảng hoặc mảng băm ... Đó là do ho thú vị điên ho ngữ nghĩa của macro tiền xử lý C.

Nếu bạn quan tâm, đây là mã: https://github.com/christianfriedl/CGenerics/blob/master/src/cgArray.h