2010-05-15 41 views
6

ngày hôm qua tôi đã đăng một câu hỏi: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?C Programming: malloc() cho một mảng 2D (sử dụng con trỏ-to-pointer)

Từ câu trả lời tôi nhận được, tôi đã có thể hiểu những gì sai lầm tôi đang làm.

Tôi đang gặp phải sự cố mới ngay bây giờ, bất kỳ ai có thể trợ giúp về vấn đề này không?

tôi muốn tự động phân bổ một mảng 2D, vì vậy tôi đi qua một con trỏ-to-Pointer từ main() tôi đến một chức năng gọi là alloc_2D_pixels(...), nơi tôi sử dụng malloc(...)for(...) vòng lặp để cấp phát bộ nhớ cho mảng 2D.

Vâng, sau khi trở về từ hàm alloc_2D_pixels(...), con trỏ trỏ đến vẫn còn NULL, vì vậy tự nhiên, khi tôi thử truy cập hoặc thử free(...) Con trỏ trỏ đến, chương trình bị treo.

Có ai có thể gợi ý cho tôi những sai lầm tôi đang làm ở đây không?

Trợ giúp !!!

Vikram


NGUỒN:

main() 
{ 


unsigned char **ptr; 
unsigned int rows, cols; 

if(alloc_2D_pixels(&ptr, rows, cols)==ERROR)  // Satisfies this condition 
    printf("Memory for the 2D array not allocated"); // NO ERROR is returned 

if(ptr == NULL)     // ptr is NULL so no memory was allocated 
    printf("Yes its NULL!");   

// Because ptr is NULL, with any of these 3 statements below the program HANGS 
ptr[0][0] = 10;      
printf("Element: %d",ptr[0][0]); 

free_2D_alloc(&ptr); 

} 


signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols) 
{ 
     signed char status = NO_ERROR; 

     memory = malloc(rows * sizeof(unsigned char**)); 

     if(memory == NULL) 
     { 
      status = ERROR; 
      printf("ERROR: Memory allocation failed!"); 

     } 
     else 
     { 
      int i; 

      for(i = 0; i< cols; i++) 
      { 
       memory[i] = malloc(cols * sizeof(unsigned char)); 

       if(memory[i]==NULL) 
       { 
        status = ERROR; 
        printf("ERROR: Memory allocation failed!"); 
       } 
      } 

     } 

    // Inserted the statements below for debug purpose only 
     memory[0][0] = (unsigned char)10;  // I'm able to access the array from 
     printf("\nElement %d",memory[0][0]); // here with no problems 


     return status; 
} 


void free_2D_pixels(unsigned char ***ptr, unsigned int rows) 
{ 
    int i; 

    for(i = 0; i < rows; i++) 
    { 
      free(ptr[i]); 
    } 

    free(ptr); 
} 

Trả lời

3

Một sai lầm là mã đăng không biên dịch :). Dưới đây là điều chỉnh mã với ý kiến ​​của tôi trong
/* kiểu này * /:

/* Next four lines get your code to compile */ 
#include <stdio.h> 
#include <stdlib.h> 
#define NO_ERROR 0 
#define ERROR 1 

/* prototypes for functions used by main but declared after main 
    (or move main to the end of the file */ 
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols); 
void free_2D_pixels(unsigned char** ptr, unsigned int rows); 

/* main should return int */ 
int main() 
{ 
    unsigned char** ptr; 
    /* need to define rows and cols with an actual value */ 
    unsigned int rows = 5, cols = 5; 

    if(alloc_2D_pixels(&ptr, rows, cols) == ERROR) // Satisfies this condition 
     printf("Memory for the 2D array not allocated"); // ERROR is returned 

    if(ptr == NULL)     // ptr is NULL so no memory was allocated 
     printf("Yes its NULL!"); 
    else 
    { 
     /* Added else clause so below code only runs if allocation worked. */ 
     /* Added code to write to every element as a test. */ 
     unsigned int row,col; 
     for(row = 0; row < rows; row++) 
      for(col = 0; col < cols; col++) 
       ptr[0][0] = (unsigned char)(row + col); 

      /* no need for &ptr here, not returning anything so no need to pass 
       by reference */ 
      free_2D_pixels(ptr, rows); 
    } 

    return 0; 
} 

signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols) 
{ 
    signed char status = NO_ERROR; 

    /* In case we fail the returned memory ptr will be initialized */ 
    *memory = NULL; 

    /* defining a temp ptr, otherwise would have to use (*memory) everywhere 
     ptr is used (yuck) */ 
    unsigned char** ptr; 

    /* Each row should only contain an unsigned char*, not an unsigned 
     char**, because each row will be an array of unsigned char */ 
    ptr = malloc(rows * sizeof(unsigned char*)); 

    if(ptr == NULL) 
    { 
     status = ERROR; 
     printf("ERROR: Memory allocation failed!"); 
    } 
    else 
    { 
     /* rows/cols are unsigned, so this should be too */ 
     unsigned int i; 

     /* had an error here. alloced rows above so iterate through rows 
      not cols here */ 
     for(i = 0; i < rows; i++) 
     { 
      ptr[i] = malloc(cols * sizeof(unsigned char)); 

      if(ptr[i] == NULL) 
      { 
       status = ERROR; 
       printf("ERROR: Memory allocation failed!"); 
       /* still a problem here, if exiting with error, 
        should free any column mallocs that were 
        successful. */ 
      } 
     } 
    } 

    /* it worked so return ptr */ 
    *memory = ptr; 
    return status; 
} 


/* no need for *** here. Not modifying and returning ptr */ 
/* it also was a bug...would've needed (*ptr) everywhere below */ 
void free_2D_pixels(unsigned char** ptr, unsigned int rows) 
{ 
    /* should be unsigned like rows */ 
    unsigned int i; 

    for(i = 0; i < rows; i++) 
    { 
     free(ptr[i]); 
    } 

    free(ptr); 
} 
+0

Hey Mark !!! :) Yeah, bạn nói đúng tôi nên đã đăng một mã số làm việc. Cảm ơn bạn đã trả lời chi tiết của bạn, tôi đánh giá cao nó. – HaggarTheHorrible

2

Trong chức năng alloc_2D_pixels của bạn, bạn cần một mức gián tiếp khi truy cập vào memory. Như bây giờ, bạn chỉ sửa đổi tham số, chứ không phải con trỏ được trỏ đến bởi tham số. Ví dụ,

memory = malloc(rows * sizeof(unsigned char**)); 
// becomes 
*memory = malloc(rows * sizeof(unsigned char**)); 

// and later... 
memory[i] = malloc(cols * sizeof(unsigned char)); 
// becomes 
(*memory)[i] = malloc(cols * sizeof(unsigned char)); 

(về cơ bản, bất cứ nơi nào bạn đang sử dụng memory, bạn cần phải sử dụng (*memory); ngoặc chỉ cần thiết khi bạn đang sử dụng kí hiệu để đảm bảo rằng các nhà khai thác được áp dụng theo đúng thứ tự)

+1

Phải là sizeof (unsigned char *) cũng chưa được ký char **. –

+0

IMHO, nó shoule thực sự là '* bộ nhớ = malloc (hàng * sizeof ** bộ nhớ)' và '(* bộ nhớ) [i] = malloc (cols * sizeof * (* bộ nhớ) [i])', tức là luôn luôn một thêm '*' trong 'sizeof'. Nhiều lỗi hơn bằng chứng. – AnT

1

Dường như, Bạn đang sử dụng các biến số rowscols chưa được khởi tạo

1

Sử dụng các mảng đa chiều theo cách này trong C là "tối ưu" để thực hiện.

Không có từ nào không rõ ràng: Vui lòng không sử dụng - và chắc chắn không khởi tạo - mảng đa chiều theo cách bạn đã minh họa. Nhiều cuộc gọi đến malloc() sẽ tạo cho bạn một loạt các vị trí bộ nhớ rời rạc không ánh xạ tốt tới cách đồ họa thực tế (như các bộ đệm đơn, liền kề) được lưu trữ ở bất kỳ đâu. Ngoài ra, nếu bạn phải làm điều đó hàng trăm hoặc hàng ngàn lần, malloc() có thể cực kỳ tốn kém.

Ngoài ra, do thực tế là bạn đang sử dụng malloc() rất thường xuyên, nó cũng là một cơn ác mộng (và lỗi để cắn bạn cuối cùng) để làm sạch. Bạn thậm chí đã đề cập rằng trong các ý kiến ​​trong mã của bạn, nhưng ... tại sao?

Nếu bạn hoàn toàn phải có ptr[rows][cols] điều này, tạo ra nó tốt hơn như thế này:

signed char alloc_2D_pixels(unsigned char*** memory, 
          unsigned int rows, 
          unsigned int cols) 
{ 
    int colspan = cols * sizeof(char); 
    int rowspan = rows * sizeof(char*); 
    unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan)); 

    /* malloc failure handling left to the reader */ 

    unsigned char *payload = ((unsigned char *)rowptrs) + rowspan; 
    int i; 
    for (i = 0; i < rows; payload += colspan, i++) 
     rowptrs[i] = payload; 
} 

cách mà bạn đang phân bổ chỉ là một khối duy nhất của bộ nhớ và toàn bộ điều có thể được trả tự do trong một đi - mương free_2D_pixels().

+0

Ah, sẽ rất ngạc nhiên nếu không ai khác trả lời câu hỏi này trong quá khứ. Tín dụng nơi tín dụng đến hạn: http://stackoverflow.com/questions/3144132/malloc-in-c-but-use-multi-dimensional-array-syntax/3144577#3144577 xem ở đó. –

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