C语言顺序表的实现

今天本来想写段代码练练手,想法挺好结果,栽了个大跟头,在这个错误上徘徊了4个小时才解决,现在分享出来,给大家提个醒,先贴上代码:

/********************************************

 * 文件名称:sqlist.h

 * 文件描述:线性表顺序存储演示

 * 文件作者:by Wang.J,in 2013.11.16

 * 文件版本:1.0

 * 修改记录:

*********************************************/

#ifndef __SQLIST_H__

#define __DWLIST_H__



#include <stdio.h>

#include <stdlib.h>

#include <string.h>



#define MAXSIZE     50

#define OK          0

#define ERR         -1



typedef int elemtype;



typedef struct {

    elemtype data[MAXSIZE];

    int      len;

}sqlist;



int init_list(sqlist *L);

int destroy_list(sqlist *L);

int list_empty(sqlist L);

int list_length(sqlist L);

int disp_list(sqlist L);

int get_elem(sqlist L, int i, elemtype *e);

int local_elem(sqlist L, elemtype e);

int list_insert(sqlist *L, int i, elemtype e);

int list_delete(sqlist *L, int i, elemtype *e);



#endif

/**************************************************

 * 文件名称:sqlist.c

 * 文件描述:线性表顺序存储的实现

 * 文件作者:by Wang.J,in 2013.11.16

 * 文件版本:1.0

 * 修改记录:

***************************************************/

#include "sqlist.h"



#if 0

#define ERR_NONE_ERROR        0

#define ERR_FUNC_EXEC         1

#define ERR_FILE_OPEN         2



char *error_msg[] = {

    /* 0  */    "成功执行,无错误",

    /* 1  */    "函数执行错误",

    /* 2  */    "文件打开错误",

};

int my_errno = 0;

#endif



int main(void)

{

    int ret = 0;

    int i = 0;

    sqlist slist;

    elemtype e;



    memset(&slist, 0, sizeof(slist));

    printf("length:%d\n", slist.len);

    ret = init_list(&slist);

    if (OK != ret)

        return -1;



    ret = list_empty(slist);

    printf("长度:%d\n", slist.len);

    if (OK == ret)

        printf("顺序表为空\n");

    if (ERR == ret)

        printf("顺序表不为空\n");



    for (i = 0; i < 10; i++) {

        e = (elemtype)i;

        list_insert(&slist, i, e);

    }

    printf("插入数据\n");



    ret = list_empty(slist);

    if (OK == ret)

        printf("顺序表为空\n");

    if (ERR == ret)

        printf("顺序表不为空\n");



    printf("after length%d\n", list_length(slist));



    disp_list(slist);



    destroy_list(&slist);



    return 0;

}



/*=====================================================

 * 函数名称:init_list

 * 函数功能:初始化一个顺序表,创建一个空的顺序表

 * 函数参数:sqlist *L   负责返回一个创建好的顺序表,如果创建

            失败则返回NULL

 * 返 回 值:成功返回0并通过指针返回一个创建好的空表

            失败返回-1指针返回NULL

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int init_list(sqlist *L)

{

    L = (sqlist *)malloc(sizeof(sqlist));



    if (NULL == L) {

        L = NULL;

        return -1;

    }



    L->len = 0;



    return 0;

}



/*=====================================================

 * 函数名称:destroy_list

 * 函数功能:销毁创建好的顺序表,释放顺序表的空间

 * 函数参数:sqlist *L,已经存在的线性表

 * 返 回 值:成功     0

            失败     -1

            通常free不会失败,其实这个函数可以直接使用void

            的,这里只是自己顺手写的,看到代码就知道不会返回0

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int destroy_list(sqlist *L)

{

    free(L);



    return 0;

}



/*=====================================================

 * 函数名称:list_empty

 * 函数功能:判断sqlist顺序表是否为空

 * 函数参数:sqlist L,已存在的线性表

 * 返 回 值:空     0

            不空   -1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int list_empty(sqlist L)

{

    if (0 == L.len)

        return 0;



    return -1;

}



/*=====================================================

 * 函数名称:list_length

 * 函数功能:取得线性表的长度,返回顺序表中元素个数

 * 函数参数:sqlist L,已经存在的线性表

 * 返 回 值:L的长度

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int list_length(sqlist L)

{

    return L.len;

}



/*=====================================================

 * 函数名称:disp_list

 * 函数功能:显示顺序表中所有的元素

 * 函数参数:sqlist L,已经存在的线性表

 * 返 回 值:成功     0

            失败     -1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int disp_list(sqlist L)

{

    int i = 0;



    if (0 >= L.len)

        return -1;



    for (i = 0; i < L.len; i++)

        printf("%d\t", L.data[i]);

    /*

     * 这个地方我自己是有异议的,首先你可能不知道输出的类型为

     * %d,再就是求长度是使用list_length函数还是使用L.len方式,

     * list_length是函数调用有着函数调用的额外开销,在PC上这点

     * 开销不算什么,但是在嵌入式系统就不得不考虑这种开销了,

     * 这基本上算是良好的移植性和代码效率之间的问题,为了提高

     * 移植性可以多添加几层抽象层,实现各种判断.除非是极其庞大

     * 的项目或是为了匹配各种这样的设备,我认为像代码定义类型这

     * 种小事,团队沟通就能解决.工作是避免问题,学习是自找问题.

     * 所以怎么取舍只能看个人了.

    */

    printf("\n");



    return 0;

}



/*=====================================================

 * 函数名称:get_elem

 * 函数功能:获取i位置元素的值域,为了方便对应i从0开始与

            数组下标一致,用e返回获取的值

 * 函数参数:sqlite L    存在的顺序表

            int    i    位置

            elemtype *e 返回值域

 * 返 回 值:成功     0

            失败     -1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int get_elem(sqlist L, int i, elemtype *e)

{

    if (i < 0 || i >= L.len) {

        e = NULL;

        return -1;

    }



    *e = L.data[i];

    /*

     * 这个地方要注意

     * 看看与e = &(L.data[i])区别

    */



    return 0;

}



/*=====================================================

 * 函数名称:local_elem

 * 函数功能:按元素值查找,返回第一个与e相匹配的元素位置

 * 函数参数:sqlist L,已经存在的顺序表

 * 返 回 值:存在返回位置

            失败返回-1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int local_elem(sqlist L, elemtype e)

{

    int i = 0;



    for (i = 0; i < L.len; i++) {

        if (e == L.data[i])

            return i;

    }



    return -1;

}



/*=====================================================

 * 函数名称:list_insert

 * 函数功能:在sqlite的i位置插入元素

 * 函数参数:sqlist *L   已存在的顺序表

            int     i   位置

            elemtype e  元素

 * 返 回 值:成功   0

            失败   -1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int list_insert(sqlist *L, int i, elemtype e)

{

    int j = 0;



    if (i < 0 || i > MAXSIZE-1)

        return -1;



    for (j = L->len; j > i; j--)

        L->data[j] = L->data[j-1];



    L->data[i] = e;

    L->len++;



    return 0;

}



/*=====================================================

 * 函数名称:list_delete

 * 函数功能:删除i位置的元素,元素通过e返回

 * 函数参数:sqlite  *L  已存在的顺序表

            int      i  位置

            elemtype *e 删除位置的元素

 * 返 回 值:成功    0

            失败    -1

 * 创 建 人:by Wang.J,in 2013.11.16

 * 修改记录:

======================================================*/

int list_delete(sqlist *L, int i, elemtype *e)

{

    int j = 0;



    if (i < 0 || i >=L->len)

        return -1;



    *e = L->data[i];

    for (j = i; j < (L->len-1); j++)

        L->data[j] = L->data[j+1];



    L->len--;



    return 0;

}

很自得,自认为写的很好,运行一下看看,

image

结果完全出乎意料.

好吧!现在分析错误!

看看main中的定义

int ret = 0;
   int i = 0;
   sqlist slist;
   elemtype e;

 

看看初始化函数init_list

int init_list(sqlist *L)
{
   L = (sqlist *)malloc(sizeof(sqlist));

    if (NULL == L) {
        L = NULL;
        return -1;
    }

    L->len = 0;

    return 0;
}

相信聪明的你已经看出来了,我在main中定义的slist空间在栈上,而我在init_list中一下子将这个东东分配到了堆空间,并且slist并不是指针,根本无法进行指向,所以结果当然就非常的错误了.

打个比方,栈和堆是两个平行的世界,只有指针是穿梭于两个世界的虫洞,除此以为其他东西无法进行跨越.

知道了原因自然很容易解决了.

由于栈上会自动分配空间所以就无需再次申请空间.所以init_list改为:

 

int init_list(sqlist *L)

{

    /*

    L = (sqlist *)malloc(sizeof(sqlist));



    if (NULL == L) {

        L = NULL;

        return -1;

    }

    */

    L->len = 0;



    return 0;

}

就可以了

大家引以为戒.

你可能感兴趣的:(C语言)