2010-10-28 30 views
10

Tôi đang gặp khó khăn khi triển khai chức năng 'bản đồ' chung trên các mảng. tôi bắt đầu với dự thảo sau:Thực hiện chức năng 'bản đồ' chung trên các mảng trong C

void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem) 
{ 
    unsigned int i = 0, j = 0; 
    void * temp = malloc(elem); 

    for(i = 0; i<n, i++) 
    { 
     temp = (f)((char *) src) + i)); 
     for(j = 0; j < elem; j++) 
     { 
     *(((char *) dest) + i) = *(((char *) temp) + i); 
     } 
    } 
    free(temp); 
} 

Tôi hiểu tại sao nó không đúng - tôi đúc để (char *) trước khi đưa nó vào 'f' - nhưng tôi tại demotivated và không thể đến với một giải pháp. (Tôi đang làm điều này trong quá trình học C)

Lý do của tôi là lấy kết quả của 'f' và, byte theo byte, sao chép nó vào dest [i].

Bạn có thể cho tôi bất kỳ gợi ý nào không?

+0

cho những gì bạn cần con trỏ này hoạt động và bản đồ bạn muốn triển khai, tôi không nghĩ bạn muốn một số bản đồ ví dụ chứa từ sgi? – Svisstack

+0

Đó là ứng dụng 'bản đồ' điển hình mà bạn có thể tìm thấy trong thực tế mọi ngôn ngữ chức năng ngoài kia. Bạn gửi một danh sách, một hàm và nó trả về danh sách được tạo thành như sau: (f (l [1]), ..., f (l [n])). – Lasirc

Trả lời

18

vấn đề đầu tiên của bạn là bạn' đang làm WAY quá nhiều trong một vài biểu thức. Bạn cần phải phá vỡ nó xuống.

void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem) 
{ 
    unsigned int i = 0, j = 0; 
    void * temp = malloc(elem); 

    char* csrc = (char*)src; 
    char* cdest = (char*)dest; 
    char* ctemp = (char*)temp; 
    for(i = 0; i<n; i++) 
    { 
     csrc++; 
     cdest++; 
     ctemp++; 
     temp = f(csrc); 
     for(j = 0; j < elem; j++) 
     { 
      cdest[i] = ctemp[i]; 
     } 
    } 
    free(temp); 
} 

Bây giờ, vấn đề thứ hai của bạn. Bạn malloc một bộ đệm, sau đó bạn .. gán cho con trỏ đó? Nhiều lần? Sau đó, chỉ miễn phí kết quả của cuộc gọi f cuối cùng? Điều này là hoàn toàn không cần thiết.

void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem) 
{ 
    unsigned int i = 0, j = 0; 

    char* csrc = (char*)src; 
    char* cdest = (char*)dest; 
    for(i = 0; i<n; i++) 
    { 
     csrc++; 
     cdest++; 
     char* ctemp = (char*)f(csrc); 
     for(j = 0; j < elem; j++) 
     { 
      cdest[i] = ctemp[i]; 
     } 
    } 
} 

Bây giờ, vấn đề thứ ba của bạn. Bạn vượt qua một con trỏ trong - nhưng chỉ để char. Bạn không vượt qua trong một khoảng trống *. Điều này có nghĩa rằng chức năng của bạn không thể được chung chung - f không thể được áp dụng cho bất cứ điều gì. Chúng ta cần một mảng void * s, để hàm có thể lấy bất kỳ kiểu nào làm đối số. Chúng ta cũng cần phải lấy kích thước của kiểu như một đối số để chúng ta biết cách di chuyển dọc theo dest.

void MapArray(void ** src, void * dest, void * (f)(void *), size_t n, size_t sizeofT) 
{ 
    for(unsigned int i = 0; i < n; i++) { 
     void* temp = f(src[n]); 
     memcpy(dest, temp, sizeofT); 
     dest = (char*)dest + sizeofT; 
    } 
} 

Chúng tôi vẫn còn một vấn đề khác - bộ nhớ tạm thời. Chúng tôi không giải phóng nó. Chúng tôi cũng không chuyển đối số dữ liệu người dùng vào f, điều này cho phép nó trả về bộ nhớ được cấp phát heap mà chúng tôi không cần phải giải phóng. Cách duy nhất trong đó f có thể làm việc là nếu nó trả về một bộ đệm tĩnh.

void MapArray(void ** src, void * dest, void * (f)(void *, void*), void* userdata, size_t n, size_t sizeofT) 
{ 
    for(unsigned int i = 0; i < n; i++) { 
     void* temp = f(src[n], userdata); 
     memcpy(dest, temp, sizeofT); 
     dest = (char*)dest + sizeofT; 
    } 
} 

Bây giờ f có thể hoạt động trên mọi thứ bạn thích và giữ bất kỳ trạng thái nào cần. Nhưng chúng tôi vẫn không giải phóng bộ đệm. Bây giờ, f trả về một cấu trúc đơn giản cho chúng ta biết nếu chúng ta cần giải phóng bộ đệm. Điều này cũng cho phép chúng tôi giải phóng hoặc không giải phóng bộ đệm trên các cuộc gọi khác nhau của f.

typedef struct { 
    void* data; 
    int free; 
} freturn; 

void MapArray(void ** src, void * dest, freturn (f)(void *, void*), void* userdata, size_t n, size_t sizeofT) 
{ 
    for(unsigned int i = 0; i < n; i++) { 
     freturn thisreturn = f(src[n], userdata); 
     void* temp = thisreturn.data; 
     memcpy(dest, temp, sizeofT); 
     dest = (char*)dest + sizeofT; 
     if (thisreturn.free) 
      free(temp); 
    } 
} 

Tuy nhiên, tôi vẫn không hiểu mục đích của chức năng này. Tất cả điều này để thay thế một vòng lặp đơn giản? Mã mà bạn đang cố gắng thay thế đơn giản hơn mã để gọi hàm của bạn và có thể hiệu quả hơn, và chắc chắn mạnh hơn (ví dụ: họ có thể sử dụng tiếp tục/ngắt).

Hơn thế nữa, C thực sự hút cho loại công việc này. C++ tốt hơn nhiều. Nó khá tầm thường ở đó để áp dụng một hàm cho mỗi thành viên của một mảng, ví dụ.

+0

Rất nhiều thông tin ngon ngọt! Cảm ơn nhiều. Nếu bạn chỉ có thể biết tôi đã học được bao nhiêu với câu trả lời của bạn! – Lasirc

1
  • Kiểm tra xem hàm f không được trả lại một con trỏ đến một biến địa phương
  • Tôi không chắc chắn những gì lặp trên j là vụ phải được làm
+0

Vòng lặp trên j là nỗ lực của tôi để sao chép, byte theo byte, đầu ra của một ứng dụng 'f' vào mục nhập 'i' của 'dest'. Tôi đã làm điều này bởi vì tôi muốn 'f' của tôi để trả về dữ liệu của kích thước biến. – Lasirc

+0

Bạn đang sử dụng 'i' bên trong vòng lặp mặc dù – srean

+0

@Lasirc: Nhưng tại thời điểm vòng lặp đó chỉ sao chép cùng một byte vào cùng một vị trí' elem' lần. Bạn cần '* (((char *) dest) + i * elem + j) = * ((char *) temp) + i * elem + j);' bên trong thay vào đó. –

2

Có lý do không có gì giống như vậy trong thư viện chuẩn C - bên cạnh việc không thể thực hiện tốt trong C. Bạn không thể sao chép kết quả, "byte theo byte" thành dest[i] - kể từ khi bạn ' đã truyền dest đến char *, nó chỉ trỏ đến một char (byte).

Có lẽ, elem được dự định được kích thước của bất cứ loại f lợi nhuận, và n là số phần tử trong srcdest. Trong trường hợp đó, mã của bạn không phải là quá xa, nhưng (như bạn đã phỏng đoán) cách bạn đang thao tác các con trỏ (đặc biệt là các diễn viên để char *) sẽ không cắt nó.

Ngay cả khi bạn khắc phục điều đó, tuy nhiên, bạn sẽ có một vấn đề khác: chỉ định kiểu trả về từ f mà không biết loại sẽ thực sự (thực sự) khó khăn. Trong thực tế, khoảng cách duy nhất tôi có thể nghĩ đến là để bọc mã này lên thành một vĩ mô thay vì:

#define MapArray(s, d, f, n) \ 
do {       \ 
    unsigned i;    \ 
    for (i = 0; i<n; i++)  \ 
     d[i] = f(s[i]);  \ 
} while (0) 

Bạn muốn sử dụng một cái gì đó như thế này này:

int f(int a) { return a + 100; } 

#define elements(array) (sizeof(array)/sizeof(array[0])) 

int main() { 
    unsigned i; 
    int x[] = { 0, 1, 2, 3}; 
    int y[elements(x)]; 

    MapArray(x, y, f, elements(x)); 

    for (i=0; i<elements(x); i++) 
     printf("%d\n", y[i]); 
    return 0; 
} 

Hãy lưu ý: Tôi m không phải đề xuất điều này. một cách để làm những gì bạn được yêu cầu, nhưng như tôi đã nói để bắt đầu, điều này là không thể làm tốt trong C. Mã này hoạt động ở một mức độ nào đó, nhưng IMO nó không đủ điều kiện làm việc công việc tốt.

Các vấn đề liên quan