指针实例

来源:互联网 发布:dota2 arteezy 知乎 编辑:程序博客网 时间:2024/06/06 04:39

用c语言写个小程序,其中要处理一个表格文件。这个文件的信息就是一张表,例如:

num    name    sex    age    score addr
101    Ray    Male    24    87.5    Beijing Road
102    Simon    Female    28    99    Shanghai Road.China
103    Mason    Male    25    100    Zhangjiang.Road


每个字段的分割符是Tab(也就是'/t')。现在程序要求可以随机访问表中的字段。经分析,表中的列数可以是固定的,用数组就可以表示出来,想具体访问哪个字段,直接array[field]即可。然后表格的行数就是文件的行数,这样以来表格就可以看成一个二维数组。但是每个字段是一个字符串,并且每个字符串的大小不能确定。
所以正好用一个三级指针来表示整张表格。由于行数,列数和字段长度不确定,这里动态分配内存。

程序很简单,关键的地方有一点:
三级指针的内存分配和释放。
第一步分配三级指针的内存,为表格所有行分配空间。 即
    ptable->ptable_info = (char***)malloc(ptable->table_row * sizeof(char**));
让三级指针ptable->ptable_info指向row个连续地址二级指针的起始地址。

第二步分配二级指针的地址,为表格一行中所有列分配空间。即
    *(ptable->ptable_info) = (char**)malloc(MAX_FIELD * sizeof(char*));
让二级指针*(ptable->ptable_info)指向colum个连续地址一级指针的起始地址。

第三步分配一级指针的地址,为表格一行中某列分配空间。即
    *one_trace = (char*) malloc((strlen(one_line)+1) * sizeof(char));
让一级指针*one_trace指向字段字符串的地址。

释放内存空间则是相反的过程,类似c++中基类和派生类,构造函数和析构函数的调用顺序。

 

程序如下:

/*
 * Print all the table info based on a table file.
 *
 * Usage : parse_table table_filename
 *
 * 
 */


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

#define true 1
#define false 0

/*The max characters of a line*/
#define MAX_LINE_NUMBER 200

#ifndef NULL
#define NULL 0
#endif

//#define DEBUG


enum table_field{
        NUM = 0,
        NAME,
        SEX,
        AGE,
        SCORE,
        ADDR,
        MAX_FIELD = 6
};

typedef struct table_info_type {
        char*** ptable_info;
        int table_row;
        int table_col;
}table_info;

table_info my_table;

void usage(void)
{
        printf("Usage : parse_table table_filename/n");
        exit(true);
}

/*
 * Return the line number of a file.
 */

int cal_file_lines(FILE *fp)
{
        char line[MAX_LINE_NUMBER];
        int count;
        if(!fp) return -1;
        rewind(fp);
        count = 0;
        while(!feof(fp))
        {
                fgets(line, MAX_LINE_NUMBER, fp);
                ++count;
        }
        return count-1;
}

/* Function: Parse one row of table, and save to pointers to pointers
 * Input: string
 * Output: pointers to pointers
 */

int parse_table_row(char* one_line, char** one_trace)
{
        int switch_tag[MAX_FIELD];
        char *result, *temp_line;
        char** temp_trace;
        int field = 0;
        int loop;
        result = temp_line = NULL;
        temp_trace = one_trace;
// backup

        temp_line = one_line;

#ifdef DEBUG
        printf("begin to parse one line/n");
#endif
        if(!one_line) return -1;
        if(!one_trace) {printf("one_trace is NULL/n"); return -1;}
       
        for(loop = 0; loop < MAX_FIELD; loop++)
                switch_tag[loop] =-1;
      
       
        /* Split string taking '/t' as delimiters*/
        result = strchr(one_line, '/t');
        while(NULL != result)
        {
                *result = '/0';
// Now '/0' is delimiter

                /* Record the position where the delimiters is changed */
                switch_tag[field] = result - temp_line;
                *one_trace = (char*) malloc((strlen(one_line)+1) * sizeof(char));
                if(!*one_trace) {printf("Macalloc memory failed/n"); return -1;}
                strcpy(*one_trace, one_line);
                one_trace++, field++;
                one_line = result + 1;
                result = strchr(one_line, '/t');
        }
        /*Don't foret last field*/
        *one_trace = (char*) malloc((strlen(one_line)+1) * sizeof(char));
        strcpy(*one_trace, one_line);


        
/*Now temp_line is pointer to the last field. Recovery one_line,
        * so that free the memory. Otherwise, memory leak!*/

        one_line = temp_line;
        one_trace = temp_trace;
        for(field = 0; field < MAX_FIELD; field++)
                if(switch_tag[field] != -1)
                        one_line[switch_tag[field]] = '/t';

#ifdef DEBUG
        for(field = 0; field < MAX_FIELD; field++)
        {
             printf("%s/t", one_trace[field]);
        }
        printf("/n");
#endif
        result = temp_line = NULL;
        temp_trace = NULL;
        return true;
}

/* Function: According to input file which contains trace table, save table info to a pointer
 * to pointer to pointer.
 * Input: file handler
 * Output: table_info
 */

int setup_table_info(FILE *fp, table_info *ptable)
{
        int row, result, len;
        char*** temp_table;
        char line[MAX_LINE_NUMBER];
        if(!fp) return -1;
        ptable->table_row = cal_file_lines(fp);
        ptable->table_col = MAX_FIELD;
        if(ptable->table_row == 0)
        {
                ptable->ptable_info = NULL;
                return true;
        }

        /*malloc enough memory for table rows.*/
        ptable->ptable_info = (char***)malloc(ptable->table_row * sizeof(char**));
        temp_table = ptable->ptable_info;
        if(!ptable->ptable_info) return -1;
        rewind(fp);
        for(row = 0; row < ptable->table_row; row++)
        {
                fgets(line, MAX_LINE_NUMBER, fp);
                /*Skip the new line characters "/n"*/
                len = strlen(line);
                line[len-1] = '/0';
                /*malloc memory for table coloum.*/
                *(ptable->ptable_info) = (char**)malloc(MAX_FIELD * sizeof(char*));
                if(*(ptable->ptable_info) == NULL) return -1;
                result = parse_table_row(line, *(ptable->ptable_info));
                if (result == -1) return -1;
                (ptable->ptable_info)++;
        }

        ptable->ptable_info = temp_table;
        temp_table = NULL;
        return true;
}

/*
 * Free memory.
 */

int cleanup_table_info(table_info *ptable)
{
        int i,j;
        if (ptable->ptable_info == NULL) return true;

        for(i = 0; i < ptable->table_row; i++)
        {
                for(j = 0; j < ptable->table_col; j++)
                        if(((ptable->ptable_info)[i][j]) != NULL)
                                free(((ptable->ptable_info)[i][j]));

                if (((ptable->ptable_info)[i]) != NULL)
                        free((ptable->ptable_info)[i]);
               
        }

        if(ptable->ptable_info != NULL)
                free(ptable->ptable_info);

        return true;
}

/*
 * Print table.
 *
 */

int print_table(table_info table)
{
        int i,j;
        if (table.ptable_info == NULL) return -1;
        for(i = 0; i < table.table_row; i++)
        {
                for(j = 0; j < table.table_col; j++)
                        printf("%s/t", (table.ptable_info)[i][j]);
                printf("/n");
        }

        return true;
}

int main(int argc, char** argv)
{
        char *filename;
        FILE *file;
        int result;

        /* The argc must be two! */
        if (argc != 2) usage();
        /* Setup environment */
        filename = argv[1];
        if (filename == NULL)
        {
                printf("File name can't be null/n");
                usage();
        }

        /* Check file */
        if ((file = fopen(filename, "r")) == NULL)
        {
                printf("%s doesn't exist/n", filename);
                usage();
        } else {
                printf("Begin to parse %s/n", filename);
        }

        /* setup table info */
        result = setup_table_info(file, &my_table);
        if (result == -1) {printf("setup_database failed/n");exit(1);}

        result = print_table(my_table);
        if (result == -1) {printf("trace table is blank!/n");exit(1);}

        /*Cleanup */
        cleanup_table_info(&my_table);
        fclose(file);

        return true;