分类目录归档:编程

shell命令单行和多行注释

单行注释

# echo "hello world"

多行注释

#!/bin/bash
# author: lne
# url: lne.cc

echo "hello world"

# v1
: '
echo "hello world"
echo 'hello world'
echo `ls -l; mkdir 1`
'
# v2
:<<"eof"
echo "hello world"
echo 'hello world'
echo `ls -l; mkdir 1`
eof

# v3
:<<'!'
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
!false
!

# v4
:<<\EOF
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
EOF

# v5 注释中不能有单独"}", 包含可导致语法错误
((0)) && {
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
}

# v5 注释中不能有单独"}", 包含可导致语法错误
false && {
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
}

# v6 注释中不能有单独"fi", 包含可导致语法错误
if false; then
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
fi

# v7 注释中不能有单独"done", 包含可意外结束循环
while false; do
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v8 注释中不能有单独"done", 包含可意外结束循环
while :; do
break
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v9 注释中不能有单独"done", 包含可意外结束循环
for false; do
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v10 注释中不能有单独"done", 包含可意外结束循环
for ((;;)); do
break
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v11 注释中不能有单独"done", 包含可意外结束循环
until true; do
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v12 注释中不能有单独"done", 包含可意外结束循环
until :; do
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
done

# v13 注释中不能有单独"EOF", 包含可意外结束循环
<<"EOF"
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
EOF

# v14 将注释放到函数中
function comment() {
echo "hello world!"
echo 'hello world'
echo `ls -l; mkdir 1`
}


最大公约数和最小公倍数

欧几里德算法

欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:

定理:gcd(a,b) = gcd(b,a mod b)

证明:a可以表示成a = kb + r,则r = a mod b
假设d是a,b的一个公约数,则有
d|a, d|b,而r = a – kb,因此d|r
因此d是(b,a mod b)的公约数

假设d 是(b,a mod b)的公约数,则
d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公约数

因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证

最小公倍数等于两个数的乘积除以最大公约数

/*
7-26 最大公约数和最小公倍数(15 分)

本题要求两个给定正整数的最大公约数和最小公倍数。
输入格式:

输入在一行中给出两个正整数M和N(≤1000)。
输出格式:

在一行中顺序输出M和N的最大公约数和最小公倍数,两数字间以1空格分隔。
输入样例:

511 292

输出样例:

73 2044

*/
#include <stdio.h>

int gcd(int, int);
int rec_gcd(int, int);
int lcm(int, int);
int main(void)
{
        int m, n;
        int g, l;
        scanf("%d%d", &m, &n);
        g = gcd(m, n);
        l = lcm(m, n);

        printf("%d %d\n", g, l);

        return 0;
}

int gcd(int u, int v)
{
        int r;
        while (v) {
                r = u % v;
                u = v;
                v = r;
        }

        return u;
}

int rec_gcd(int u, int v)
{
        if (!v)
                return u;
        else
                return rec_gcd(v, u % v);
}

int lcm(int u, int v)
{
        int r = gcd(u, v);
//      int l = u * (v / r);
//      int l = v * (u / r);
        int l = u * v / r;

        return l;
}


运行结果:

[lhf@lhf programming]$ ./26
511 292
73 2044

实现C语言的继承和多态

较经典的动物世界中的实例来举例:
假设动物们(包括人)都会吃(Eat),会走(Walk),会说(Talk),而派生类为 dog(汪星人) 和 cat(喵星人),当然还可以是更多,dog 和 cat 都有自己独特的 eat, walk 和 talk 方式,那么大致的代码如下:
代码无警告编译运行

基类头文件

// animal.h
#ifndef ANIMAL_H__
#define ANIMAL_H__

typedef struct animal_s_ animal_t;
typedef struct animal_ops_s_ animal_ops_t;

struct animal_s_ {
        char *name;
        animal_ops_t *animal_ops;
};

struct animal_ops_s_ {
        void (*eat)(char *);
        void (*walk)(int);
        void (*talk)(char *);
};

animal_t *animal_init(char *name);

void animal_eat(animal_t *, char *food);
void animal_walk(animal_t *, int steps);
void animal_talk(animal_t *, char *msg);

void animal_die(animal_t *);

#endif//ANIMAL_H__

基类实现

// animal.c
#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "animal.h"

animal_t *animal_init(char *name)
{
        assert(name != NULL);
        size_t name_len = strlen(name);

        animal_t *animal = malloc(sizeof (*animal)
                + sizeof (animal_ops_t) + name_len + 1);
        memset(animal, 0, sizeof (*animal)
                + sizeof (animal_ops_t) + name_len + 1);
        animal->name = (char *)animal
                + sizeof (animal_t) + sizeof (animal_ops_t);
        memcpy(animal->name, name, name_len);
        animal->animal_ops = (animal_ops_t *)((char *)animal
                + sizeof (*animal));

        return animal;
}

void animal_eat(animal_t *animal, char *food)
{
        animal->animal_ops->eat(food);

        return;
}

void animal_walk(animal_t *animal, int steps)
{
        animal->animal_ops->walk(steps);

        return;
}

void animal_talk(animal_t *animal, char *msg)
{
        animal->animal_ops->talk(msg);

        return;
}

void animal_die(animal_t *animal)
{
        assert(animal != NULL);
        free(animal);

        return;
}

继续阅读

C语言输出菱形图像

使用C语言输出如下图像

思路:确定每行开始位置,和该行’*’的总个数。
代码文件,该图形可以整体右移,请调节 #define LEFT 1 参数

[lhf@localhost work]$ cat diamond.c
/**
 *     *
 *    * *
 *   * * *
 *    * *
 *     *
 */
#include <stdio.h>
#define LEFT 1  // right shift space

int main(void)
{
        int size = 0;
        printf("Input side number of diamond: ");
        scanf("%d", &size);
        int len = size * 2 - 1;
        int high = len;
        int width = len + LEFT;
        char diamond[high][width];

        const char dia = '*';
        const char pidd = ' ';

//      begin of start and number of diamond
        int begin = 0, n;
        for (int i = 0; i < high; i++) {
                if (i < size) {
                        begin = size - i - 1 + LEFT;
                        n = i + 1;
                } else {
                        begin = i - size + 1;
                        n = size - begin;
                        begin += LEFT;
                }
                for (int j = 0; j < width; j++) {
                        if ((j == begin) && (n--)) {
                                putchar(dia);
                                begin += 2;
                        } else
                                putchar(pidd);
                }
                putchar('\n');
        }

        return 0;
}

c++ primer 5 exercise 10.9

c++ primer 5 exercise 10.9

实现自己的elimDups程序。测试你的程序,分别在读取输入后、调用unique后以及调用erase后打印vector
程序实现:

// sort and elimDups
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::ends;
using std::endl;
using std::string;
using std::vector;
using std::sort;
using std::unique;

vector<string> strToVec(const string line, const string separators);
void show(vector<string> const &words);
void elimDups(vector<string> words);
int main(void)
{
        const string Separators = " \t:;,\n\r\f\v";
        string str("the quick red fox jumps the slow red turtle");

        // string turn on vector<sting>
        vector<string> vec;
        vec = strToVec(str, Separators);

        // show vector<string>
        cout << "string to vector<sting>..." << endl;
        show(vec);

        // elimDups()
        cout << "\nelimDups()..." << endl;
        elimDups(vec);

        return 0;
}

vector<string> strToVec(const string line, const string separators)
{
        vector<string> vec;
        string word;
        std::string::size_type startPos = 0, endPos = 0;
        std::string::size_type wordLen = 0;

        while ((startPos = line.find_first_not_of(separators,
                endPos)) != std::string::npos) {
                endPos = line.find_first_of(separators, startPos);
                if (endPos == std::string::npos)
                        wordLen = line.size() - startPos;
                else
                        wordLen = endPos - startPos;
                word.assign(line.begin() + startPos,
                        line.begin() + startPos + wordLen);
                vec.push_back(word);
        }

        return vec;
}

void show(vector<string> const &words)
{
        for (const auto s : words)
                cout << s << " ";
        cout << endl;

        return;
}

void elimDups(vector<string> words)
{
        sort(words.begin(), words.end());
        show(words);

        auto end_unique = unique(words.begin(), words.end());
        show(words);

        words.erase(end_unique, words.end());
        show(words);

        return;
}

程序测试结果:

[lhf@localhost 10-9]$ ./elimDups
string to vector<sting>...
the quick red fox jumps the slow red turtle

elimDups()...
fox jumps quick red red slow the the turtle
fox jumps quick red slow the turtle the red
fox jumps quick red slow the turtle

字符串排序函数(单词排序,唯一)

本程序演示:怎样将一个string字符串输入到一个vector中,每个元素对应一个单词。

// sort and unique
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::ends;
using std::endl;
using std::string;
using std::vector;
using std::sort;

void show(vector<string> const &words);
void elimDups(vector<string> &words);
int main(void)
{
        string str("the quick red fox jumps over the slow red turtle");
        //string str("");

        string separators = " \t:;,\v\n\r\f";
        string word;
        vector<string> vec;
        std::string::size_type startPos = 0, endPos = 0;
        std::string::size_type /*count = 0,*/ wordLen = 0;
        while ((startPos = str.find_first_not_of(separators, endPos))
                != std::string::npos) {
//              ++count;
                endPos = str.find_first_of(separators, startPos);
                if (endPos == std::string::npos) {
                        wordLen = str.size() - startPos;
                } else {
                        wordLen = endPos -startPos;
                }
                word.assign(str.begin() + startPos,
                        str.begin() + startPos + wordLen);
                vec.push_back(word);
        }
        // show vec info
        show(vec);

        elimDups(vec);

        return 0;
}

void elimDups(vector<string> &words)
{
        sort(words.begin(), words.end());
        show(words);
        auto end_unique = unique(words.begin(), words.end());
        show(words);
        words.erase(end_unique, words.end());
        show(words);
}

void show(vector<string> const &words)
{
        for (auto s : words)
                cout << s << " ";
        cout << endl;

        return;
}


程序输出:

[lhf@localhost study]$ ./23
the quick red fox jumps over the slow red turtle
fox jumps over quick red red slow the the turtle
fox jumps over quick red slow the turtle the red
fox jumps over quick red slow the turtle

c++primer 9.51习题

设计一个类,它有三个unsigned成员,分别表示年月日。为其编写构造函数,接受一个表示日期的string参数。你的构造函数能够处理不同的数据格式,如January 1, 1900 1/1/1900 Jan 1 1900等

// January 1, 1900      1/1/1900        Jan 1 1900
#include <iostream>
#include <vector>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::ends;
using std::vector;
using std::string;
using std::stoi;

class Date {
public:
        vector<string> full_month{
                "January", "February", "March", "April", "May", "June", "July",
                "August", "September", "October", "November", "December"
        };
        vector<string> abb_month{
                "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept",
                "Sep", "Oct", "Nov", "Dec"
        };
public:
        Date(const string& info);
        ~Date(void) {}
        void print_info(void)
        {
                cout << "_" << month << "." << day << "."<< year << "_\n";
                return;
        }
private:
        void init(void)
        {
                year = 1900;
                month = 1;
                day = 1;

                return;
        }
private:
        unsigned year;
        unsigned month;
        unsigned day;
};

int main(void)
{

        cout << "2343" << endl;
        Date error("2343");
        error.print_info();
        cout << string(20, '*') << endl;

        cout << "October 21, 2002" << endl;
        Date date1("October 21, 2002");
        date1.print_info();
        cout << string(20, '*') << endl;

        cout << "2/8/1995" << endl;
        Date date2("2/8/1995");
        date2.print_info();
        cout << string(20, '*') << endl;

        cout << "May 12 2011" << endl;
        Date date3("May 12 2011");
        date3.print_info();

        return 0;
}

Date::Date(const string& info)
{
        std::string::size_type pos;
        pos = info.find_first_of(", /");

        // error info
        if (pos == std::string::npos) {
                init();
                cout << "error date format: init" << endl;
                return;
        }

        // 1/1/1900
        std::string::size_type pos1 = info.find_first_of('/'),
                pos11 = pos1;
        if (pos1 != std::string::npos) {
                day = stoi(info.substr(0, pos1));
                pos11 = info.find_first_of('/', pos1 + 1);
                month = stoi(info.substr(pos1 + 1, pos11));
                year = stoi(info.substr(pos11 + 1, info.size() - 1));
                return;
        }

        // January 1, 1990 and Jan 1 1900
        std::string::size_type pos2 = info.find_first_of(' '),
                pos3 = pos2, pos33 = pos3, pos22 = info.find_first_of(',');
        if (pos22 != std::string::npos) {
                // January 1, 1990
                string str_month = info.substr(0, pos2);
                vector<string>::size_type n = 0;
                for (; n != full_month.size(); ++n) {
                        if (!full_month[n].compare(str_month))
                                break;
                }
                if (n == full_month.size()) {
                        init();
                        cout << "format(January 1, 1990) error: init" << endl;
                        return;
                } else {
                        month = n + 1;
                }
                day = stoi(info.substr(pos2 + 1, pos22));
                year = stoi(info.substr(pos22 + 1, info.size() -1));

                return;
        } else if (info.find_first_of(' ', pos3 + 1) != std::string::npos) {
                // Jan 1 1990
                vector<string>::size_type n = 0;
                string str_month = info.substr(0, pos3);
                for (; n != abb_month.size(); ++n) {
                        if (!abb_month[n].compare(str_month))
                                break;
                }
                if (n == abb_month.size()) {
                        init();
                        cout << "format(Jan 1 1990) error: init" << endl;
                        return;
                } else if (n < 9) {
                        month = n + 1;
                } else if (n == 9) {
                        month = n;
                } else {
                        month = n - 1;
                }
                pos33 = info.find_first_of(' ', pos3 + 1);
                day = stoi(info.substr(pos3 + 1, pos33));
                year = stoi(info.substr(pos33 + 1, info.size() - 1));
        } else {
                init();
                cout << "other error format: init" << endl;

                return;
        }

        return;
}

测试运行结果:

$ ./my_date
2343
error date format: init
_1.1.1900_
********************
October 21, 2002
_10.21.2002_
********************
2/8/1995
_8.2.1995_
********************
May 12 2011
_5.12.2011_

简单哈希表(hash table c)

hash表,有时候也被称为散列表。

引自wiki: 散列表(Hash table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
下面我们可以写一个简单的hash操作代码。

定义哈希表数据类型

/* hash.h */
#include <stdbool.h>

#ifndef HASH_H
#define HASH_H

typedef struct _NODE {
        int data;
        struct _NODE *next;
} NODE;

typedef struct _HASH_TABLE {
        NODE *value[10];
} HASH_TABLE;

HASH_TABLE *create_hash_table(void);
NODE *find_data_in_hash(HASH_TABLE *pHashTab, int data);
void print_hash_table(HASH_TABLE *pHashTab);
bool insert_data_into_hash(HASH_TABLE *pHashTab, int data);
bool delete_data_from_hash(HASH_TABLE *pHashTab, int data);
bool delete_idx_data_from_hash(HASH_TABLE *pHashTab, int idx);
bool delete_all_data_from_hash(HASH_TABLE *pHashTab);
bool reset_hash_table(HASH_TABLE *pHashTab);
bool destroy_hash_table(HASH_TABLE **ppHashTab);

#endif//HASH_H

继续阅读

C数据类型的DWORD

C数据类型的长度

类型  ILP32(位数)     LP64(位数)
char        8            8
short      16            16
int        32            32
long       32            64
long long  64            64
point      32            64

宏定义

    WORD       ->   unsigned   short 
    DWORD      ->   unsigned   int 
    LPVOID     ->   void   * 
    UINT       ->   unsigned   int 

按文件名存储-哈希表

通过散列函数将数据值和它的存储位置联系起来。即通过精心地向表载入元素实现,从而提高访问速度。本例中采取的解决冲突的办法是建立一个链表,挂在这个位置的后面,所有散列函数值为这个位置的元素都添加到这个链表中,可以从头部插入也可以从尾部追加,甚至可以再这个位置后面再挂一个散列表。代码实现了将文件名按字母a-z分类,不区分大小写。先以数组存储各节点,当发生冲突后即将节点加入链表中。然后遍历显示所有的文件名。

/* a2z.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define HASHSIZE 26
#define FILENAMELENGTH 20
#define TRUE 1
#define FALSE 0

struct file {
        char name[FILENAMELENGTH];
        struct file *next;
};

struct file * files[HASHSIZE];

char case_insensitive(char ch)
{
        if (isupper(ch))
                return ch - 'A' + 'a';
        return ch;
}

void init(void)
{
        int i;
        for (i = 0; i < HASHSIZE; i++)
                files[i] = NULL;
}

int hash(char *s)
{
        return case_insensitive(s[0]) - 'a';
}

int search(char *s)
{
        int num = hash(s);
        if (files[num] != NULL) {
                struct file *p = files[num];
                while (p != NULL) {
                        if (strcmp(p->name, s) == 0)
                                return TRUE;
                        p = p->next;
                }
        }

        return FALSE;
}

void insert(char *s)
{
        if (search(s) == FALSE) {
                int num = hash(s);
                struct file *new_node = malloc(sizeof (struct file));
                strcpy(new_node->name, s);
                if (files[num] == NULL) {
                        files[num] = new_node;
                        files[num]->next = NULL;
                } else {
                        new_node->next = files[num];
                        files[num] = new_node;
                }
        }

        return;
}

void free_node(struct file *p)
{
        free(p);

        return;
}


void del_node(char *s)
{
        if (search(s) == TRUE) {
                struct file *p = files[hash(s)], *q;
                if (strcmp(p->name, s) == 0) {
                        q = p;
                        files[hash(s)] = p->next;
                        free_node(q);
                } else {
                        while (p != NULL) {
                                q = p;
                                p = p->next;
                                if (strcmp(p->name, s) == 0)
                                        free_node(q);
                        }
                }
        }

        return;
}


void del(int num)
{
        struct file *p =files[num], *q;
        while (p != NULL) {
                q = p;
                p = p->next;
                free(q);
        }

        return;
}

void destroy(void)
{
        int i;

        for (i = 0; i < HASHSIZE; i++)
                del(i);

        return;
}

void show(int num)
{
        struct file *p = files[num];
        if (p != NULL) {
                printf("For file begins with '%c': \n", num + 'a');
                while (p != NULL) {
                        printf("%s\n", p->name);
                        p = p->next;
                }
                printf("\n");
        }



}

void show_all(void)
{
        int i;
        for (i = 0; i < HASHSIZE; i++)
                show(i);

        return;
}

int main(void)
{
        char * file_name[] = {
                "apple", "because", "song", "Dan", "discuz", "cartoon",
                "nobody", "android", "information", "love", "like", "No",
                "nothing", "like", "alone", "nothing", "sizeof", "Yes",
        };

        int len = sizeof file_name / sizeof (char *);
        int i;
        for (i = 0; i < len; i++)
                insert(file_name[i]);
        show_all();

        printf("---------------------------------\n");
        del_node("like");
        show_all();
        destroy();

        return 0;
}

继续阅读