Chinaunix首页 | 论坛 | 博客
  • 博客访问: 449440
  • 博文数量: 45
  • 博客积分: 2526
  • 博客等级: 少校
  • 技术积分: 478
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-12 21:04
文章分类

全部博文(45)

文章存档

2014年(1)

2011年(1)

2010年(3)

2009年(22)

2008年(18)

我的朋友

分类: C/C++

2008-05-13 23:17:16

最近不得不用c语言写个小程序(其实用shell, perl等脚本相当简单),其中要处理一个表格文件。这个文件的信息就是一张表,例如:

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]即可。然后表格的行数就是文件的行数,这样以来表格就可以看成一个二维数组。但是每个字段是一个字符串,并且每个字符串的大小不能确定。
所以正好用一个三级指针来表示整张表格。由于行数,列数和字段长度不确定,这里动态分配内存。

程序很简单,关键的地方有两点:
1。三级指针的内存分配和释放。
第一步分配三级指针的内存,为表格所有行分配空间。 即
    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++中基类和派生类,构造函数和析构函数的调用顺序。
可以用valgrind来检查程序是否有内存泄露。关于valgrind,在Fedora下,yum install valgrind即可安装。
具体造作以后有时间再介绍吧。

2。分析表格中的一行。
实际上就是分割字符串。用到c标准库函数strchr.
  #include 
char *strchr( const char *str, int ch );
The function strchr() returns a pointer to the first occurence of ch in str, or NULL if ch is not found.

还有一个更简单的函数strtok
  #include 
char *strtok( char *str1, const char *str2 );
The strtok() function returns a pointer to the next "token" in str1, where str2
contains the delimiters that determine the token. strtok() returns NULL if no
token is found. In order to convert a string to tokens, the first call
to strtok() should have str1 point to the string to be tokenized. All calls after
this should have str1 be NULL.

For example:
  char str[] = "now # is the time for all # good men to come to the # aid of their country";
   
char delims[] = "#";
   
char *result = NULL;
   result
= strtok( str, delims );
   
while( result != NULL ) {
       printf
( "result is \"%s\"\n", result );
       result
= strtok( NULL, delims );
   
}    

The above code will display the following output:
   result is "now "
   result
is " is the time for all "
   result
is " good men to come to the "
   result
is " aid of their country"  



附上程序。

/*
 * Print all the table info based on a table file.
 *
 * Usage : parse_table table_filename
 *
 * Author : Ray Chen
 * Date : 2008-5-7
 */


#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;
}

阅读(2451) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

dorainm2008-06-06 14:04:42

恩,以前我写的一个操作 MySQL数据库,也用到了类似这样子的一个表结构 http://blog.chinaunix.net/u1/41420/showart_341362.html 源码里面,d_table就是封装的,实现内存中一张表结构的库