zoukankan      html  css  js  c++  java
  • 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
    ", slist.len);
        ret = init_list(&slist);
        if (OK != ret)
            return -1;
    
        ret = list_empty(slist);
        printf("长度:%d
    ", slist.len);
        if (OK == ret)
            printf("顺序表为空
    ");
        if (ERR == ret)
            printf("顺序表不为空
    ");
    
        for (i = 0; i < 10; i++) {
            e = (elemtype)i;
            list_insert(&slist, i, e);
        }
        printf("插入数据
    ");
    
        ret = list_empty(slist);
        if (OK == ret)
            printf("顺序表为空
    ");
        if (ERR == ret)
            printf("顺序表不为空
    ");
    
        printf("after length%d
    ", 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	", L.data[i]);
        /*
         * 这个地方我自己是有异议的,首先你可能不知道输出的类型为
         * %d,再就是求长度是使用list_length函数还是使用L.len方式,
         * list_length是函数调用有着函数调用的额外开销,在PC上这点
         * 开销不算什么,但是在嵌入式系统就不得不考虑这种开销了,
         * 这基本上算是良好的移植性和代码效率之间的问题,为了提高
         * 移植性可以多添加几层抽象层,实现各种判断.除非是极其庞大
         * 的项目或是为了匹配各种这样的设备,我认为像代码定义类型这
         * 种小事,团队沟通就能解决.工作是避免问题,学习是自找问题.
         * 所以怎么取舍只能看个人了.
        */
        printf("
    ");
    
        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;
    }

    就可以了

    大家引以为戒.

  • 相关阅读:
    抓包的原理
    在ASP.NET MVC中使用JQ插件datatable
    如何禁用Visual Studio 2013的Browser Link功能
    SVN中tag branch trunk用法详解
    ASP.NET MVC和jQuery DataTable整合
    随便看的
    SQL查询今天、昨天、7天内、30天
    在DataTable数据类型最后增加一列,列名为“Column”,内容都为“AAA”
    validform表单验证插件最终版
    context.Session[“xxx”]详解
  • 原文地址:https://www.cnblogs.com/wangluojisuan/p/3426904.html
Copyright © 2011-2022 走看看