提交以前完成的内容,不包括习题33
This commit is contained in:
parent
d6bbef323b
commit
c96f3a6d48
|
@ -0,0 +1,235 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "ef4fb02d-b70b-40f3-be0f-434711ed87b4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"stack = [3, 4, 5]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "4fe740fe-162e-4763-8592-be87b412d26c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4, 5, 6, 7]"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.append(6)\n",
|
||||
"stack.append(7)\n",
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "411d9f9d-ccaf-415c-b858-0601deb058d5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"7"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "caf7d327-1f51-4e64-bb2e-5ae73e03a14b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4, 5, 6]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "8bad3ba9-6a5e-4c4e-a7f3-09349cb7ab3e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"6"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "797f814d-b722-4bc2-8321-2055d3b35ba5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"5"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "530dcc1e-032d-4eb8-9081-a49aa7c502ee",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4]"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "8596fc1a-c27a-41d7-9ed2-06d1065fe028",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"4"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "086f3233-5106-477a-8419-0889afbb96fb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "2c7a7eb0-4831-48bd-8479-f89b1eafae3d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "IndexError",
|
||||
"evalue": "pop from empty list",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mstack\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpop\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[0;31mIndexError\u001b[0m: pop from empty list"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a63b26d3-d21d-4258-ab34-26870d562318",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex17 ex17_test ex17v2 stack
|
||||
|
||||
clean:
|
||||
rm -f ex17 ex17_test ex17v2 stack
|
|
@ -0,0 +1,235 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "ef4fb02d-b70b-40f3-be0f-434711ed87b4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"stack = [3, 4, 5]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "4fe740fe-162e-4763-8592-be87b412d26c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4, 5, 6, 7]"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.append(6)\n",
|
||||
"stack.append(7)\n",
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "411d9f9d-ccaf-415c-b858-0601deb058d5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"7"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "caf7d327-1f51-4e64-bb2e-5ae73e03a14b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4, 5, 6]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "8bad3ba9-6a5e-4c4e-a7f3-09349cb7ab3e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"6"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "797f814d-b722-4bc2-8321-2055d3b35ba5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"5"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "530dcc1e-032d-4eb8-9081-a49aa7c502ee",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[3, 4]"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "8596fc1a-c27a-41d7-9ed2-06d1065fe028",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"4"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "086f3233-5106-477a-8419-0889afbb96fb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "2c7a7eb0-4831-48bd-8479-f89b1eafae3d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "IndexError",
|
||||
"evalue": "pop from empty list",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mstack\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpop\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[0;31mIndexError\u001b[0m: pop from empty list"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stack.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a63b26d3-d21d-4258-ab34-26870d562318",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,264 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA 512
|
||||
#define MAX_ROWS 100
|
||||
|
||||
struct Address {
|
||||
int id;
|
||||
int set;
|
||||
char name[MAX_DATA];
|
||||
char email[MAX_DATA];
|
||||
};
|
||||
|
||||
struct Database {
|
||||
struct Address rows[MAX_ROWS];
|
||||
};
|
||||
|
||||
struct Connection {
|
||||
FILE *file;
|
||||
struct Database *db;
|
||||
};
|
||||
|
||||
void die(const char *message)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR: %s\n", message);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Address_print(struct Address *addr)
|
||||
{
|
||||
printf("%d %s %s\n", addr->id, addr->name, addr->email);
|
||||
}
|
||||
|
||||
void Database_load(struct Connection *conn)
|
||||
{
|
||||
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1 )
|
||||
{
|
||||
die("Failed to load database.");
|
||||
}
|
||||
}
|
||||
|
||||
struct Connection *Database_open(const char *filename, char mode)
|
||||
{
|
||||
struct Connection *conn = malloc(sizeof(struct Connection));
|
||||
if (!conn)
|
||||
{
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
conn->db = malloc(sizeof(struct Database));
|
||||
if (!conn->db)
|
||||
{
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
if (mode == 'c')
|
||||
{
|
||||
conn->file = fopen(filename, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->file = fopen(filename, "r+");
|
||||
|
||||
if (conn->file)
|
||||
{
|
||||
Database_load(conn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->file)
|
||||
{
|
||||
die("Failed to open the file");
|
||||
}
|
||||
|
||||
return conn;
|
||||
};
|
||||
|
||||
void Database_close(struct Connection *conn)
|
||||
{
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_write(struct Connection *conn)
|
||||
{
|
||||
rewind(conn->file);
|
||||
|
||||
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1)
|
||||
{
|
||||
die("Failed to write database.");
|
||||
}
|
||||
|
||||
rc = fflush(conn->file);
|
||||
if (rc == -1)
|
||||
{
|
||||
die("Cannot flush database.");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_create(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
// make a prototype to initialize it
|
||||
struct Address addr = {.id = i, .set = 0};
|
||||
// then just assign it
|
||||
conn->db->rows[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
void Database_set(struct Connection *conn, int id, const char *name, const char *email)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
if (addr->set)
|
||||
{
|
||||
die("Already set, delete it first");
|
||||
}
|
||||
|
||||
addr->set = 1;
|
||||
// WARNING: bug, read the "How To Break It" and fix this
|
||||
char *res = strncpy(addr->name, name, MAX_DATA);
|
||||
// demonstrate the strncpy bug
|
||||
if (!res)
|
||||
{
|
||||
die("Name copy failed");
|
||||
}
|
||||
|
||||
res = strncpy(addr->email, email, MAX_DATA);
|
||||
if (!res)
|
||||
{
|
||||
die("Email copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_get(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
Address_print(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
die("ID is not set");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_delete(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address addr = {.id = id, .set = 0};
|
||||
conn->db->rows[id] = addr;
|
||||
}
|
||||
|
||||
void Database_list(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
if (cur->set)
|
||||
{
|
||||
Address_print(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
die("USAGE: ex17 <dbfile><action> [action params]");
|
||||
}
|
||||
|
||||
char *filename = argv[1];
|
||||
char action = argv[2][0];
|
||||
struct Connection *conn = Database_open(filename, action);
|
||||
int id = 0;
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
id = atoi(argv[3]);
|
||||
}
|
||||
if (id >= MAX_ROWS)
|
||||
{
|
||||
die("There's not that many records.");
|
||||
}
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case 'c':
|
||||
Database_create(conn);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need an id to get");
|
||||
}
|
||||
|
||||
Database_get(conn, id);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (argc != 6)
|
||||
{
|
||||
die("Need id, name, email to set");
|
||||
}
|
||||
|
||||
Database_set(conn, id, argv[4], argv[5]);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need id to delete");
|
||||
}
|
||||
|
||||
Database_delete(conn, id);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
Database_list(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid action: c=create, g=get, s=set, l=list");
|
||||
}
|
||||
|
||||
Database_close(conn);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA 512
|
||||
#define MAX_ROWS 100
|
||||
|
||||
struct Address {
|
||||
int id;
|
||||
int set;
|
||||
char name[MAX_DATA];
|
||||
char email[MAX_DATA];
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Database {
|
||||
struct Address rows[MAX_ROWS];
|
||||
};
|
||||
|
||||
struct Connection {
|
||||
FILE *file;
|
||||
struct Database *db;
|
||||
};
|
||||
|
||||
// void die(const char *message)
|
||||
void die(const char *message, struct Connection *conn)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR: %s\n", message);
|
||||
}
|
||||
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Address_print(struct Address *addr)
|
||||
{
|
||||
// printf("%d %s %s\n", addr->id, addr->name, addr->email);
|
||||
printf("%d %s %s %d\n", addr->id, addr->name, addr->email, addr->height);
|
||||
}
|
||||
|
||||
void Database_load(struct Connection *conn)
|
||||
{
|
||||
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1 )
|
||||
{
|
||||
die("Failed to load database.", conn);
|
||||
}
|
||||
}
|
||||
|
||||
struct Connection *Database_open(const char *filename, char mode)
|
||||
{
|
||||
struct Connection *conn = malloc(sizeof(struct Connection));
|
||||
if (!conn)
|
||||
{
|
||||
die("Memory error", conn);
|
||||
}
|
||||
|
||||
conn->db = malloc(sizeof(struct Database));
|
||||
if (!conn->db)
|
||||
{
|
||||
die("Memory error", conn);
|
||||
}
|
||||
|
||||
if (mode == 'c')
|
||||
{
|
||||
conn->file = fopen(filename, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->file = fopen(filename, "r+");
|
||||
|
||||
if (conn->file)
|
||||
{
|
||||
Database_load(conn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->file)
|
||||
{
|
||||
die("Failed to open the file", conn);
|
||||
}
|
||||
|
||||
return conn;
|
||||
};
|
||||
|
||||
void Database_close(struct Connection *conn)
|
||||
{
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_write(struct Connection *conn)
|
||||
{
|
||||
rewind(conn->file);
|
||||
|
||||
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1)
|
||||
{
|
||||
die("Failed to write database.", conn);
|
||||
}
|
||||
|
||||
rc = fflush(conn->file);
|
||||
if (rc == -1)
|
||||
{
|
||||
die("Cannot flush database.", conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_create(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
// make a prototype to initialize it
|
||||
struct Address addr = {.id = i, .set = 0};
|
||||
// then just assign it
|
||||
conn->db->rows[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_set(struct Connection *conn, int id, const char *name, const char *email)
|
||||
void Database_set(struct Connection *conn, int id, const char *name,
|
||||
const char *email, int height)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
die("Already set, delete it first", conn);
|
||||
}
|
||||
|
||||
addr->set = 1;
|
||||
|
||||
addr->height = height;
|
||||
// WARNING: bug, read the "How To Break It" and fix this
|
||||
char *res = strncpy(addr->name, name, MAX_DATA);
|
||||
|
||||
addr->name[MAX_DATA - 1] = '\0';
|
||||
// demonstrate the strncpy bug
|
||||
if (!res)
|
||||
{
|
||||
die("Name copy failed", conn);
|
||||
}
|
||||
|
||||
res = strncpy(addr->email, email, MAX_DATA);
|
||||
addr->email[MAX_DATA - 1] = '\0';
|
||||
if (!res)
|
||||
{
|
||||
die("Email copy failed", conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_get(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
Address_print(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
die("ID is not set", conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_delete(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address addr = {.id = id, .set = 0};
|
||||
conn->db->rows[id] = addr;
|
||||
}
|
||||
|
||||
void Database_list(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
if (cur->set)
|
||||
{
|
||||
Address_print(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database_find(struct Connection *conn, const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
// printf("%s v.s. %s\n", cur->name, name);
|
||||
if ((cur->set)&&(!strcmp(cur->name, name)))
|
||||
{
|
||||
printf("%d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct Connection *conn = NULL;
|
||||
if (argc < 3)
|
||||
{
|
||||
die("USAGE: ex17 <dbfile><action> [action params]", conn);
|
||||
}
|
||||
|
||||
char *filename = argv[1];
|
||||
char action = argv[2][0];
|
||||
// struct Connection *conn = Database_open(filename, action);
|
||||
conn = Database_open(filename, action);
|
||||
int id = 0;
|
||||
char name[MAX_DATA];
|
||||
// int i = 0;
|
||||
int height = 0;
|
||||
|
||||
printf("size: %ld\n", sizeof(struct Database));
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
id = atoi(argv[3]);
|
||||
|
||||
height = atoi(argv[6]);
|
||||
}
|
||||
if (id >= MAX_ROWS)
|
||||
{
|
||||
die("There's not that many records.", conn);
|
||||
}
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case 'c':
|
||||
Database_create(conn);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need an id to get", conn);
|
||||
}
|
||||
|
||||
Database_get(conn, id);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Nedd a name to find", conn);
|
||||
}
|
||||
// WARNING: no boundary check, the length of argv[3] may longer than MAX_DATA
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; argv[3][i] != '\0'; ++i)
|
||||
{
|
||||
name[i] = argv[3][i];
|
||||
}
|
||||
name[i] = '\0';
|
||||
|
||||
Database_find(conn, name);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
// if (argc != 6)
|
||||
if (argc != 7)
|
||||
{
|
||||
// die("Need id, name, email to set", conn);
|
||||
die("Need id, name, email, height to set", conn);
|
||||
}
|
||||
|
||||
// Database_set(conn, id, argv[4], argv[5]);
|
||||
Database_set(conn, id, argv[4], argv[5], height);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need id to delete", conn);
|
||||
}
|
||||
|
||||
Database_delete(conn, id);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
Database_list(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid action: c=create, g=get, s=set, l=list", conn);
|
||||
}
|
||||
|
||||
Database_close(conn);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA 512
|
||||
#define MAX_ROWS 100
|
||||
struct Connection *conn = NULL;
|
||||
|
||||
|
||||
struct Address {
|
||||
int id;
|
||||
int set;
|
||||
char name[MAX_DATA];
|
||||
char email[MAX_DATA];
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Database {
|
||||
struct Address rows[MAX_ROWS];
|
||||
};
|
||||
|
||||
struct Connection {
|
||||
FILE *file;
|
||||
struct Database *db;
|
||||
};
|
||||
|
||||
// void die(const char *message)
|
||||
// void die(const char *message, struct Connection *conn)
|
||||
void die(const char *message)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR: %s\n", message);
|
||||
}
|
||||
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Address_print(struct Address *addr)
|
||||
{
|
||||
// printf("%d %s %s\n", addr->id, addr->name, addr->email);
|
||||
printf("%d %s %s %d\n", addr->id, addr->name, addr->email, addr->height);
|
||||
}
|
||||
|
||||
// void Database_load(struct Connection *conn)
|
||||
void Database_load(struct Connection *thisConn)
|
||||
{
|
||||
// printf("hello123%ld", sizeof(struct Database));
|
||||
int rc = fread(thisConn->db, sizeof(struct Database), 1, thisConn->file);
|
||||
|
||||
if (rc != 1 )
|
||||
{
|
||||
// die("Failed to load database.", conn);
|
||||
die("Failed to load database.");
|
||||
}
|
||||
}
|
||||
|
||||
struct Connection *Database_open(const char *filename, char mode)
|
||||
{
|
||||
struct Connection *conn = malloc(sizeof(struct Connection));
|
||||
if (!conn)
|
||||
{
|
||||
// die("Memory error", conn);
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
conn->db = malloc(sizeof(struct Database));
|
||||
if (!conn->db)
|
||||
{
|
||||
// die("Memory error", conn);
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
if (mode == 'c')
|
||||
{
|
||||
conn->file = fopen(filename, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->file = fopen(filename, "r+");
|
||||
|
||||
if (conn->file)
|
||||
{
|
||||
Database_load(conn);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->file)
|
||||
{
|
||||
// die("Failed to open the file", conn);
|
||||
die("Failed to open the file");
|
||||
}
|
||||
|
||||
return conn;
|
||||
};
|
||||
|
||||
// void Database_close(struct Connection *conn)
|
||||
void Database_close()
|
||||
{
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_write(struct Connection *conn)
|
||||
void Database_write()
|
||||
{
|
||||
rewind(conn->file);
|
||||
|
||||
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1)
|
||||
{
|
||||
// die("Failed to write database.", conn);
|
||||
die("Failed to write database");
|
||||
}
|
||||
|
||||
rc = fflush(conn->file);
|
||||
if (rc == -1)
|
||||
{
|
||||
// die("Cannot flush database.", conn);
|
||||
die("Cannot flush database.");
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_create(struct Connection *conn)
|
||||
void Database_create()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
// make a prototype to initialize it
|
||||
struct Address addr = {.id = i, .set = 0};
|
||||
// then just assign it
|
||||
conn->db->rows[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_set(struct Connection *conn, int id, const char *name, const char *email)
|
||||
// void Database_set(struct Connection *conn, int id, const char *name,
|
||||
// const char *email, int height)
|
||||
void Database_set(int id, const char *name, const char *email, int height)
|
||||
{
|
||||
printf("hello");
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
// die("Already set, delete it first", conn);
|
||||
die("Already set, delete it first");
|
||||
}
|
||||
|
||||
addr->set = 1;
|
||||
|
||||
addr->height = height;
|
||||
// WARNING: bug, read the "How To Break It" and fix this
|
||||
char *res = strncpy(addr->name, name, MAX_DATA);
|
||||
|
||||
addr->name[MAX_DATA - 1] = '\0';
|
||||
// demonstrate the strncpy bug
|
||||
if (!res)
|
||||
{
|
||||
// die("Name copy failed", conn);
|
||||
die("Name copy failed");
|
||||
}
|
||||
|
||||
res = strncpy(addr->email, email, MAX_DATA);
|
||||
addr->email[MAX_DATA - 1] = '\0';
|
||||
if (!res)
|
||||
{
|
||||
// die("Email copy failed", conn);
|
||||
die("Eamil copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_get(struct Connection *conn, int id)
|
||||
void Database_get(int id)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
Address_print(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// die("ID is not set", conn);
|
||||
die("ID is not set");
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_delete(struct Connection *conn, int id)
|
||||
void Database_delete(int id)
|
||||
{
|
||||
struct Address addr = {.id = id, .set = 0};
|
||||
conn->db->rows[id] = addr;
|
||||
}
|
||||
|
||||
// void Database_list(struct Connection *conn)
|
||||
void Database_list()
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
if (cur->set)
|
||||
{
|
||||
Address_print(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void Database_find(struct Connection *conn, const char *name)
|
||||
void Database_find(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
// printf("%s v.s. %s\n", cur->name, name);
|
||||
if ((cur->set)&&(!strcmp(cur->name, name)))
|
||||
{
|
||||
printf("%d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// struct Connection *conn = NULL;
|
||||
if (argc < 3)
|
||||
{
|
||||
// die("USAGE: ex17 <dbfile><action> [action params]", conn);
|
||||
die("USAGE: ex17 <dbfile><action> [action params]");
|
||||
}
|
||||
|
||||
char *filename = argv[1];
|
||||
char action = argv[2][0];
|
||||
// struct Connection *conn = Database_open(filename, action);
|
||||
conn = Database_open(filename, action);
|
||||
int id = 0;
|
||||
char name[MAX_DATA];
|
||||
// int i = 0;
|
||||
int height = 0;
|
||||
|
||||
printf("size: %ld\n", sizeof(struct Database));
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
id = atoi(argv[3]);
|
||||
|
||||
height = atoi(argv[6]);
|
||||
}
|
||||
if (id >= MAX_ROWS)
|
||||
{
|
||||
// die("There's not that many records.", conn);
|
||||
die("There's not that many records.");
|
||||
}
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case 'c':
|
||||
// Database_create(conn);
|
||||
Database_create();
|
||||
// Database_write(conn);
|
||||
Database_write();
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (argc != 4)
|
||||
{
|
||||
// die("Need an id to get", conn);
|
||||
die("Need an id to get");
|
||||
}
|
||||
|
||||
// Database_get(conn, id);
|
||||
Database_get(id);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (argc != 4)
|
||||
{
|
||||
// die("Nedd a name to find", conn);
|
||||
die("Need a name to find");
|
||||
}
|
||||
// WARNING: no boundary check, the length of argv[3] may longer than MAX_DATA
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; argv[3][i] != '\0'; ++i)
|
||||
{
|
||||
name[i] = argv[3][i];
|
||||
}
|
||||
name[i] = '\0';
|
||||
|
||||
// Database_find(conn, name);
|
||||
Database_find(name);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
// if (argc != 6)
|
||||
if (argc != 7)
|
||||
{
|
||||
// die("Need id, name, email to set", conn);
|
||||
// die("Need id, name, email, height to set", conn);
|
||||
die("Need id, name, email, height to set");
|
||||
}
|
||||
|
||||
printf("hello");
|
||||
// Database_set(conn, id, argv[4], argv[5]);
|
||||
// Database_set(conn, id, argv[4], argv[5], height);
|
||||
Database_set(id, argv[4], argv[5], height);
|
||||
// Database_write(conn);
|
||||
Database_write();
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (argc != 4)
|
||||
{
|
||||
// die("Need id to delete", conn);
|
||||
die("Need id to delete");
|
||||
}
|
||||
|
||||
// Database_delete(conn, id);
|
||||
Database_delete(id);
|
||||
// Database_write(conn);
|
||||
Database_write();
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
// Database_list(conn);
|
||||
Database_list();
|
||||
break;
|
||||
|
||||
default:
|
||||
// die("Invalid action: c=create, g=get, s=set, l=list", conn);
|
||||
die("Invalid action: c=create, g=get, s=set, l=list");
|
||||
}
|
||||
|
||||
// Database_close(conn);
|
||||
Database_close();
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,95 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_STACK_SIZE 4
|
||||
|
||||
int push(int top, int stack_array[]);
|
||||
int pop(int top, int stack_array[]);
|
||||
int show(int top, int stack_array[]);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int choice = 0;
|
||||
int top = -1;
|
||||
int stack_array[MAX_STACK_SIZE] = {0};
|
||||
|
||||
while (choice != 4)
|
||||
{
|
||||
printf("\nPerform operations on the stack:");
|
||||
printf("\n1. Push the element\n2. Pop the element\n3. Show\n4. End");
|
||||
printf("\n\nEnter the choice: ");
|
||||
scanf("%d", &choice);
|
||||
|
||||
switch(choice)
|
||||
{
|
||||
case 1:
|
||||
top = push(top, stack_array);
|
||||
break;
|
||||
case 2:
|
||||
top = pop(top, stack_array);
|
||||
break;
|
||||
case 3:
|
||||
top = show(top, stack_array);
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("\nInvalid choice!");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int push(int top, int stack_array[])
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
if (top == MAX_STACK_SIZE - 1)
|
||||
{
|
||||
printf("\nOverflow!");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\nEnter the element to be added onto the stack:");
|
||||
scanf("%d", &x);
|
||||
top = top + 1;
|
||||
stack_array[top] = x;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
int pop(int top, int stack_array[])
|
||||
{
|
||||
if (-1 == top)
|
||||
{
|
||||
printf("\nUnderflow!");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\nPopped element: %d", stack_array[top]);
|
||||
top = top - 1;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
int show(int top, int stack_array[])
|
||||
{
|
||||
if (-1 == top)
|
||||
{
|
||||
printf("\nStack is empty!");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\nElements present in the stack: \n");
|
||||
for (int i = top; i >= 0; --i)
|
||||
{
|
||||
printf("%d\n", stack_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
|
||||
make clean
|
||||
make ex17_test
|
||||
./ex17_test db.dat c
|
||||
./ex17_test db.dat s 1 zed zed@zedshaw.com 167
|
||||
./ex17_test db.dat s 2 frank frank@zedshaw.com 177
|
||||
./ex17_test db.dat s 3 joe joe@zedshaw.com 187
|
||||
./ex17_test db.dat l
|
||||
./ex17_test db.dat g 3
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
|
||||
make clean
|
||||
make ex17v2
|
||||
./ex17v2 db.dat c
|
||||
./ex17v2 db.dat s 1 zed zed@zedshaw.com 167
|
||||
./ex17v2 db.dat s 2 frank frank@zedshaw.com 177
|
||||
./ex17v2 db.dat s 3 joe joe@zedshaw.com 187
|
||||
./ex17v2 db.dat l
|
||||
./ex17v2 db.dat g 3
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex18 ex18_test
|
||||
|
||||
clean:
|
||||
rm -f ex18 ex18_test
|
|
@ -0,0 +1,126 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// Our old friend die from ex17.
|
||||
void die(const char *message)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// a typedef creates a fake type,.in this case for a function pointer
|
||||
typedef int(*compare_cb)(int a, int b);
|
||||
|
||||
// ***************************************
|
||||
// A classic bubble sort function that uses the compare_cb to do the sorting.
|
||||
int *bubble_sort(int *numbers, int count, compare_cb cmp)
|
||||
{
|
||||
int temp = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int *target = malloc(count * sizeof(int));
|
||||
|
||||
if (!target)
|
||||
{
|
||||
die("Memory error.");
|
||||
}
|
||||
|
||||
memcpy(target, numbers, count * sizeof(int));
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
for (j = 0; j < count - 1; ++j)
|
||||
{
|
||||
if (cmp(target[j], target[j + 1]) > 0)
|
||||
{
|
||||
temp = target[j + 1];
|
||||
target[j + 1] = target[j];
|
||||
target[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
int sorted_order(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int reverse_order(int a, int b)
|
||||
{
|
||||
return b - a;
|
||||
}
|
||||
|
||||
int strange_order(int a, int b)
|
||||
{
|
||||
if (0 == a || 0 == b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************************
|
||||
// Used to test that we are sorting things correctly
|
||||
// by doing the sort and printing it out.
|
||||
void test_sorting(int *numbers, int count, compare_cb cmp)
|
||||
{
|
||||
int i = 0;
|
||||
int *sorted = bubble_sort(numbers, count, cmp);
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
die("Failed to sort as requested.");
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
printf("%d ", sorted[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(sorted);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
die("USAGE: ex18 4 3 1 5 6");
|
||||
}
|
||||
|
||||
int count = argc - 1;
|
||||
int i = 0;
|
||||
char **inputs = argv + 1;
|
||||
|
||||
// count times sizeof(int)
|
||||
int *numbers = malloc(count * sizeof(int));
|
||||
if (!numbers)
|
||||
{
|
||||
die("Memory error.");
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
numbers[i] = atoi(inputs[i]);
|
||||
}
|
||||
|
||||
test_sorting(numbers, count, sorted_order);
|
||||
test_sorting(numbers, count, reverse_order);
|
||||
test_sorting(numbers, count, strange_order);
|
||||
|
||||
free(numbers);
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,184 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// Our old friend die from ex17.
|
||||
void die(const char *message)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// a typedef creates a fake type,.in this case for a function pointer
|
||||
typedef int(*compare_cb)(int a, int b);
|
||||
|
||||
typedef int*(*sort)(int *numbers, int count, compare_cb cmp);
|
||||
|
||||
// ***************************************
|
||||
// A classic bubble sort function that uses the compare_cb to do the sorting.
|
||||
int *bubble_sort(int *numbers, int count, compare_cb cmp)
|
||||
{
|
||||
int temp = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int *target = malloc(count * sizeof(int));
|
||||
|
||||
if (!target)
|
||||
{
|
||||
die("Memory error.");
|
||||
}
|
||||
|
||||
memcpy(target, numbers, count * sizeof(int));
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
for (j = 0; j < count - 1; ++j)
|
||||
{
|
||||
if (cmp(target[j], target[j + 1]) > 0)
|
||||
{
|
||||
temp = target[j + 1];
|
||||
target[j + 1] = target[j];
|
||||
target[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
int *selection_sort(int *numbers, int count, compare_cb cmp)
|
||||
{
|
||||
int temp = 0;
|
||||
int *target = malloc(count * sizeof(int));
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int index = 0;
|
||||
|
||||
if (!target)
|
||||
{
|
||||
die("Memory error.");
|
||||
}
|
||||
|
||||
memcpy(target, numbers, count * sizeof(int));
|
||||
|
||||
// One by one move boundary of unsorted subarray
|
||||
for (i = 0; i < count - 1; ++i)
|
||||
{
|
||||
// Find the minimum element in unsorted array
|
||||
index = i;
|
||||
for (j = i + 1; j < count; ++j)
|
||||
{
|
||||
if (cmp(target[j], target[index]) < 0 )
|
||||
{
|
||||
index = j;
|
||||
}
|
||||
}
|
||||
temp = target[index];
|
||||
target[index] = target[i];
|
||||
target[i] = temp;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
int sorted_order(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int reverse_order(int a, int b)
|
||||
{
|
||||
return b - a;
|
||||
}
|
||||
|
||||
// int bad_order(int a, int b, int c)
|
||||
// {
|
||||
// return a - b;
|
||||
// }
|
||||
|
||||
int strange_order(int a, int b)
|
||||
{
|
||||
if (0 == a || 0 == b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************************
|
||||
// Used to test that we are sorting things correctly
|
||||
// by doing the sort and printing it out.
|
||||
// void test_sorting(int *numbers, int count, compare_cb cmp)
|
||||
void test_sort(sort s, int *numbers, int count, compare_cb cmp)
|
||||
{
|
||||
int i = 0;
|
||||
// int *sorted = bubble_sort(numbers, count, cmp);
|
||||
int *sorted = s(numbers, count, cmp);
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
die("Failed to sort as requested.");
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
printf("%d ", sorted[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(sorted);
|
||||
|
||||
unsigned char *data = (unsigned char *)cmp;
|
||||
|
||||
for(i = 0; i < 25; ++i)
|
||||
{
|
||||
printf("%2x:", data[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
die("USAGE: ex18 4 3 1 5 6");
|
||||
}
|
||||
|
||||
int count = argc - 1;
|
||||
int i = 0;
|
||||
char **inputs = argv + 1;
|
||||
|
||||
// count times sizeof(int)
|
||||
int *numbers = malloc(count * sizeof(int));
|
||||
if (!numbers)
|
||||
{
|
||||
die("Memory error.");
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
numbers[i] = atoi(inputs[i]);
|
||||
}
|
||||
|
||||
// test_sort(numbers, count, sorted_order);
|
||||
// test_sort(numbers, count, reverse_order);
|
||||
// test_sort(numbers, count, strange_order);
|
||||
test_sort(bubble_sort, numbers, count, sorted_order);
|
||||
test_sort(selection_sort, numbers, count, sorted_order);
|
||||
|
||||
test_sort(bubble_sort, numbers, count, NULL);
|
||||
// test_sort(numbers, count, NULL);
|
||||
|
||||
free(numbers);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g -DNDEBUG
|
||||
|
||||
all: ex19
|
||||
|
||||
clean:
|
||||
rm -f ex19
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define check_mem(A) check((A), "Out of memory.")
|
||||
|
||||
#define check_debug(A, M, ...) if(!(A)) {debug(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
#include "dbg.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test_debug()
|
||||
{
|
||||
// notice you don't need the \n
|
||||
debug("I have Brown Hair.");
|
||||
|
||||
// passing in arguments like printf
|
||||
debug("I am %d years old.", 37);
|
||||
}
|
||||
|
||||
void test_log_err()
|
||||
{
|
||||
log_err("I believe everthing is broken.");
|
||||
log_err("There are %d problems in %s.", 0, "space");
|
||||
}
|
||||
|
||||
void test_log_warn()
|
||||
{
|
||||
log_warn("You can safely ignore this.");
|
||||
log_warn("Maybe consider looking at: %s.", "/etc/passwd");
|
||||
}
|
||||
|
||||
void test_log_info()
|
||||
{
|
||||
log_info("Well I did something mundane.");
|
||||
log_info("It happened %f times today.", 1.3f);
|
||||
}
|
||||
|
||||
int test_check(char *file_name)
|
||||
{
|
||||
|
||||
FILE *input = NULL;
|
||||
char *block = NULL;
|
||||
|
||||
block = malloc(100);
|
||||
check_mem(block); // should work
|
||||
|
||||
input = fopen(file_name, "r");
|
||||
check(input, "Failed to open %s.", file_name);
|
||||
|
||||
free(block);
|
||||
fclose(input);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (block) {
|
||||
free(block);
|
||||
}
|
||||
if (input) {
|
||||
fclose(input);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int test_sentinel(int code)
|
||||
{
|
||||
char *temp = malloc(100);
|
||||
check_mem(temp);
|
||||
|
||||
switch (code) {
|
||||
case 1:
|
||||
log_info("It worked.");
|
||||
break;
|
||||
default:
|
||||
sentinel("I shouldn't run.");
|
||||
}
|
||||
|
||||
free(temp);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (temp)
|
||||
{
|
||||
free(temp);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int test_check_mem()
|
||||
{
|
||||
char *test = NULL;
|
||||
check_mem(test);
|
||||
|
||||
free(test);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int test_check_debug()
|
||||
{
|
||||
int i = 0;
|
||||
check_debug(i != 0, "Oops, I was 0.");
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
check(2 == argc, "Need an argument.");
|
||||
|
||||
test_debug();
|
||||
// test_log_err();
|
||||
// test_log_warn();
|
||||
test_log_info();
|
||||
|
||||
check(0 == test_check("ex19.c"), "failed with ex19.c");
|
||||
check(-1 == test_check(argv[1]), "failed with argv");
|
||||
check(0 == test_sentinel(1), "test_sentinel failed.");
|
||||
check(-1 == test_sentinel(100), "test_sentinel failed.");
|
||||
check(-1 == test_check_mem(), "test_check_mem failed.");
|
||||
check(-1 == test_check_debug(), "test_check_debug failed.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex21
|
||||
|
||||
clean:
|
||||
rm -f ex21
|
|
@ -0,0 +1,249 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int integer = 55;
|
||||
double num1 = 0.1;
|
||||
float num2 = 0.2;
|
||||
char ch = 'a';
|
||||
void *thing = NULL;
|
||||
enum weather{Sunny, Rainy, Cloudy};
|
||||
enum weather today = Cloudy;
|
||||
|
||||
printf("%d %f %f %c %p %d\n", integer, num1, num2, ch, thing, today);
|
||||
|
||||
unsigned int num3 = 65533;
|
||||
signed int num4 = 700000000;
|
||||
long int num5 = 700000000000;
|
||||
short int num6 = 65500;
|
||||
|
||||
printf("%u %d %ld %d\n", num3, num4, num5, num6);
|
||||
|
||||
const int num7 = 123;
|
||||
volatile int num8 = 567;
|
||||
register int num9 = 890;
|
||||
|
||||
// num7 = 1;
|
||||
printf("%d %d %d\n", num7, num8, num9);
|
||||
|
||||
long num10 = 567;
|
||||
char ch2 = '9';
|
||||
int num11 = 890;
|
||||
double num12 = 10.1;
|
||||
|
||||
printf("%lf\n", (double)num10 - (double)ch2 - (double)num11 * num12);
|
||||
|
||||
int8_t num13 = 130;
|
||||
int16_t num14 = 130;
|
||||
int32_t num15 = 130;
|
||||
int64_t num16 = 130;
|
||||
|
||||
uint8_t num17 = 130;
|
||||
uint16_t num18 = 130;
|
||||
uint32_t num19 = 130;
|
||||
uint64_t num20 = 130;
|
||||
|
||||
printf("int8: %d %d %d\n", num13, INT8_MAX, INT8_MIN);
|
||||
printf("int16: %d %d %d\n", num14, INT16_MAX, INT16_MIN);
|
||||
printf("int32: %d %d %d\n", num15, INT32_MAX, INT32_MIN);
|
||||
printf("int64: %ld %ld %ld\n", num16, INT64_MAX, INT64_MIN);
|
||||
|
||||
printf("uint8: %d %d\n", num17, UINT8_MAX);
|
||||
printf("uint16: %d %d\n", num18, UINT16_MAX);
|
||||
printf("uint32: %d %u\n", num19, UINT32_MAX);
|
||||
printf("uint64: %ld %lu\n", num20, UINT64_MAX);
|
||||
|
||||
int_least8_t num21 = 111;
|
||||
int_least16_t num22 = 33333;
|
||||
int_least32_t num23 = 4444;
|
||||
int_least64_t num24 = 55555;
|
||||
|
||||
uint_least8_t num25 = 123;
|
||||
uint_least16_t num26 = 444;
|
||||
uint_least32_t num27 = 666;
|
||||
uint_least64_t num28 = 999;
|
||||
|
||||
printf("int_least8: %d %d %d\n", num21, INT_LEAST8_MAX, INT_LEAST8_MIN);
|
||||
printf("int_least16: %d %d %d\n", num22, INT_LEAST16_MAX, INT_LEAST16_MIN);
|
||||
printf("int_least32: %d %d %d\n", num23, INT_LEAST32_MAX, INT_LEAST32_MIN);
|
||||
printf("int_least64: %ld %ld %ld\n", num24, INT_LEAST64_MAX, INT_LEAST64_MIN);
|
||||
|
||||
printf("uint_least8_t: %u %u\n", num25, UINT_LEAST8_MAX);
|
||||
printf("uint_least16_t: %u %u\n", num26, UINT_LEAST16_MAX);
|
||||
printf("uint_least32_t: %u %u\n", num27, UINT_LEAST32_MAX);
|
||||
printf("uint_least64_t: %lu %lu\n", num28, UINT_LEAST64_MAX);
|
||||
|
||||
int_fast8_t num29 = 111;
|
||||
int_fast16_t num30 = 222;
|
||||
int_fast32_t num31 = 444;
|
||||
int_fast64_t num32 = 666;
|
||||
|
||||
uint_fast8_t num33 = 123;
|
||||
uint_fast16_t num34 = 222;
|
||||
uint_fast32_t num35 = 444;
|
||||
uint_fast64_t num36 = 666;
|
||||
|
||||
printf("int_fast8: %d %d %d\n", num29, INT_FAST8_MAX, INT_FAST8_MIN);
|
||||
printf("int_fast16: %ld %ld %ld\n", num30, INT_FAST16_MAX, INT_FAST16_MIN);
|
||||
printf("int_fast32: %ld %ld %ld\n", num31, INT_FAST32_MAX, INT_FAST32_MIN);
|
||||
printf("int_fast64: %ld %ld %ld\n", num32, INT_FAST64_MAX, INT_FAST64_MIN);
|
||||
|
||||
printf("uint_fast8: %u %u\n", num33, UINT_FAST8_MAX);
|
||||
printf("uint_fast16: %lu %lu\n", num34, UINT_FAST16_MAX);
|
||||
printf("uint_fast32: %lu %lu\n", num35, UINT_FAST32_MAX);
|
||||
printf("uint_fast64: %lu %lu\n", num36, UINT_FAST64_MAX);
|
||||
|
||||
intptr_t num37 = 123;
|
||||
uintptr_t num38 = 333;
|
||||
|
||||
printf("intptr: %ld %ld %ld\n", num37, INTPTR_MAX, INTPTR_MIN);
|
||||
printf("uintptr: %lu %lu\n", num38, UINTPTR_MAX);
|
||||
|
||||
intmax_t num39 = 666;
|
||||
uintmax_t num40 = 777;
|
||||
|
||||
printf("intmax: %ld %ld %ld\n", num39, INTMAX_MAX, INTMAX_MIN);
|
||||
printf("uintmax: %lu %lu\n", num40, UINTMAX_MAX);
|
||||
|
||||
printf("ptrdiff: %ld %ld\n", PTRDIFF_MAX, PTRDIFF_MIN);
|
||||
printf("size_t: %lu\n", SIZE_MAX);
|
||||
|
||||
// 运算符
|
||||
int a = 5;
|
||||
int b = 6;
|
||||
|
||||
printf("a*b: %d\n", a * b);
|
||||
printf("a/b: %f\n", (double)a / (double)b);
|
||||
printf("a+b: %d\n", a + b);
|
||||
printf("+a: %d\n", +a);
|
||||
printf("a++: %d\n", a++);
|
||||
printf("a: %d\n", a);
|
||||
printf("++a: %d\n", ++a);
|
||||
printf("a: %d\n", a);
|
||||
printf("a--: %d\n", a--);
|
||||
printf("a: %d\n", a);
|
||||
printf("--a: %d\n", --a);
|
||||
printf("a: %d\n", a);
|
||||
printf("a-b: %d\n", a - b);
|
||||
printf("-a: %d\n", -a);
|
||||
|
||||
struct Person
|
||||
{
|
||||
char *name;
|
||||
int age;
|
||||
int height;
|
||||
int weight;
|
||||
};
|
||||
|
||||
char name[] = "博洋";
|
||||
|
||||
struct Person *who = malloc(sizeof(struct Person));
|
||||
assert(who != NULL);
|
||||
|
||||
who -> name = strdup(name);
|
||||
who -> age = 27;
|
||||
who -> height = 181;
|
||||
who -> weight = 160;
|
||||
|
||||
printf("My name is %s\n", who -> name);
|
||||
printf("I am %d years old.\n", who -> age);
|
||||
printf("I am %d cm tall.\n", who -> height);
|
||||
printf("I am %f kg fat.\n", (double)(who -> weight) / (double)2);
|
||||
|
||||
struct Person who2;
|
||||
|
||||
who2.name = "王博洋\0";
|
||||
who2.age = 27;
|
||||
who2.height = 181;
|
||||
who2.weight = 160;
|
||||
|
||||
printf("My name is %s\n", who2.name);
|
||||
printf("I am %d years old.\n", who2.age);
|
||||
printf("I am %d cm tall.\n", who2.height);
|
||||
printf("I am %f kg fat.\n", (double)who2.weight / (double)2);
|
||||
|
||||
int arr[4] = {1, 3, 5, 6};
|
||||
|
||||
printf("sizeof arr: %ld\n", sizeof(arr));
|
||||
|
||||
int *p = arr;
|
||||
|
||||
printf("address: %p %p %p\n", p, (p + 1), &p);
|
||||
printf("arr[1]: %d\n", *(p + 1));
|
||||
|
||||
double c = 5.0000001;
|
||||
double d = 5.0000002;
|
||||
// int e = 5;
|
||||
|
||||
if (c != d)
|
||||
{
|
||||
printf("c != b\n");
|
||||
}
|
||||
|
||||
if (c < d)
|
||||
{
|
||||
printf("c < d\n");
|
||||
}
|
||||
|
||||
if (c <= d)
|
||||
{
|
||||
printf("c <= d\n");
|
||||
}
|
||||
|
||||
if (c == d)
|
||||
{
|
||||
printf("c == d\n");
|
||||
}
|
||||
|
||||
if (c > d)
|
||||
{
|
||||
printf(" c > d\n");
|
||||
}
|
||||
|
||||
if (c >= d)
|
||||
{
|
||||
printf(" c >= d\n");
|
||||
}
|
||||
|
||||
int e = 255;
|
||||
int f = 256;
|
||||
|
||||
printf(" hex: e:%x f:%x\n", e, f);
|
||||
printf("e&f: %x\n", e&f);
|
||||
printf("e >> 1: %x\n", e >> 1);
|
||||
printf("e<<1: %x\n", e << 1);
|
||||
printf("e^f: %x\n", e^f);
|
||||
printf("e|f: %x\n", e|f);
|
||||
printf("~e+1: %x\n", ~e + 1);
|
||||
|
||||
int g = 0;
|
||||
int h = 1;
|
||||
|
||||
if (g)
|
||||
{
|
||||
printf("g is true\n");
|
||||
}
|
||||
|
||||
if (!g)
|
||||
{
|
||||
printf(" g is not true\n");
|
||||
}
|
||||
|
||||
if (g&&h)
|
||||
{
|
||||
printf("g&&h is true\n");
|
||||
}
|
||||
|
||||
if (g||h)
|
||||
{
|
||||
printf("g||h is true\n");
|
||||
}
|
||||
|
||||
g?printf("g is true\n") : printf("g is false\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
all: ex22_main
|
||||
|
||||
ex22_main: ex22.o ex22_main.c
|
||||
cc -Wall -g -DNDEBUG ex22_main.c ex22.o -o ex22_main
|
||||
|
||||
ex22.o: ex22.c
|
||||
cc -Wall -g -DNDEBUG -c -o ex22.o ex22.c
|
||||
|
||||
clean:
|
||||
rm -f ex22.o ex22_main
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define check_mem(A) check((A), "Out of memory.")
|
||||
|
||||
#define check_debug(A, M, ...) if(!(A)) {debug(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,71 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ex22.h"
|
||||
#include "dbg.h"
|
||||
|
||||
char *get_name(struct State *state)
|
||||
{
|
||||
return state->my_name;
|
||||
}
|
||||
|
||||
void set_name(struct State *state, char *name)
|
||||
{
|
||||
state->my_name = name;
|
||||
}
|
||||
|
||||
int get_size(struct State *state)
|
||||
{
|
||||
return state->the_size;
|
||||
}
|
||||
|
||||
void set_size(struct State *state, int size)
|
||||
{
|
||||
state->the_size = size;
|
||||
}
|
||||
|
||||
int get_age(struct State *state)
|
||||
{
|
||||
return state->the_age;
|
||||
}
|
||||
|
||||
void set_age(struct State *state, int age)
|
||||
{
|
||||
state->the_age = age;
|
||||
}
|
||||
|
||||
double update_ratio(double new_ratio)
|
||||
{
|
||||
static double ratio = 1.0;
|
||||
|
||||
double old_ratio = ratio;
|
||||
ratio = new_ratio;
|
||||
|
||||
return old_ratio;
|
||||
}
|
||||
|
||||
void print_size(struct State *state)
|
||||
{
|
||||
log_info("I think size is: %d", state->the_size);
|
||||
}
|
||||
|
||||
void Person_destroy(struct State *who)
|
||||
{
|
||||
assert(who != NULL);
|
||||
|
||||
free(who->my_name);
|
||||
free(who);
|
||||
}
|
||||
|
||||
struct State *Person_create(char *name, int age, int size)
|
||||
{
|
||||
struct State *who = malloc(sizeof(struct State));
|
||||
|
||||
assert(who != NULL);
|
||||
who->the_age = age;
|
||||
who->the_size = size;
|
||||
who->my_name = strdup(name);
|
||||
|
||||
return who;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef _ex22_h
|
||||
#define _ex22_h
|
||||
|
||||
|
||||
struct State {
|
||||
int the_size;
|
||||
int the_age;
|
||||
char *my_name;
|
||||
};
|
||||
|
||||
// gets and sets an internal static variable in ex22.c
|
||||
int get_age(struct State *state);
|
||||
void set_age(struct State *state, int age);
|
||||
|
||||
int get_size(struct State *state);
|
||||
void set_size(struct State *state, int size);
|
||||
|
||||
char *get_name(struct State *state);
|
||||
void set_name(struct State *state, char *name);
|
||||
|
||||
// updates a static variable that's inside update_ratio
|
||||
double update_ratio(double ratio);
|
||||
|
||||
void print_size();
|
||||
|
||||
void Person_destroy(struct State *who);
|
||||
|
||||
struct State *Person_create(char *name, int age, int size);
|
||||
|
||||
#endif
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,62 @@
|
|||
#include "ex22.h"
|
||||
#include "dbg.h"
|
||||
|
||||
|
||||
void scope_demo(int count)
|
||||
{
|
||||
log_info("count is: %d", count);
|
||||
|
||||
if (count > 10 ) {
|
||||
int apple = 100; // BAD! BUGS!
|
||||
|
||||
log_info("apple in this scope is %d", apple);
|
||||
}
|
||||
|
||||
log_info("count is at exit: %d", count);
|
||||
|
||||
count = 3000;
|
||||
|
||||
log_info("count after assign: %d", count);
|
||||
|
||||
// scope_demo(3000);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct State *joe = Person_create("Joe Alex", 27, 43);
|
||||
|
||||
// test out THE_AGE accessors
|
||||
log_info("My name: %s, age: %d", get_name(joe), get_age(joe));
|
||||
|
||||
|
||||
set_age(joe, 100);
|
||||
|
||||
log_info("My age is now: %d", get_age(joe));
|
||||
|
||||
// test out THE_SIZE extern
|
||||
log_info("THE_SIZE is: %d", get_size(joe));
|
||||
print_size();
|
||||
|
||||
set_size(joe, 9);
|
||||
|
||||
log_info("THE_SIZE IS NOW: %d", get_size(joe));
|
||||
print_size();
|
||||
|
||||
// test the ratio function static
|
||||
log_info("Ratio at first: %f", update_ratio(2.0));
|
||||
log_info("Ratio again: %f", update_ratio(10.0));
|
||||
log_info("Ratio once more: %f", update_ratio(300.0));
|
||||
|
||||
// ratio = 5;
|
||||
|
||||
// test the scope demo
|
||||
int count = 4;
|
||||
scope_demo(count);
|
||||
scope_demo(count * 20);
|
||||
|
||||
log_info("count after calling scope_demo: %d", count);
|
||||
|
||||
Person_destroy(joe);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: swap
|
||||
|
||||
clean:
|
||||
rm -f swap
|
Binary file not shown.
|
@ -0,0 +1,50 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int *ptr = NULL;
|
||||
|
||||
void Swap(int a, int b)
|
||||
{
|
||||
int temp = 0;
|
||||
|
||||
temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
void Swap2(int *a, int *b)
|
||||
{
|
||||
int temp = 100;
|
||||
|
||||
*ptr = temp;
|
||||
|
||||
temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int a = 5;
|
||||
int b = 9;
|
||||
|
||||
printf("before swap\n");
|
||||
|
||||
printf("a:%d b:%d\n", a, b);
|
||||
|
||||
Swap(a, b);
|
||||
|
||||
printf("after swap\n");
|
||||
|
||||
printf("a:%d b:%d\n", a, b);
|
||||
|
||||
Swap2(&a, &b);
|
||||
|
||||
printf("after swap2\n");
|
||||
|
||||
printf("a:%d b:%d\n", a, b);
|
||||
|
||||
printf("%d\n", *ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex23 ex23_copy test
|
||||
|
||||
clean:
|
||||
rm -f ex23 ex23_copy test
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define check_mem(A) check((A), "Out of memory.")
|
||||
|
||||
#define check_debug(A, M, ...) if(!(A)) {debug(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dbg.h"
|
||||
|
||||
int normal_copy(char *from, char *to, int count)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
to[i] = from[i];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int duffs_device(char *from, char *to, int count)
|
||||
{
|
||||
{
|
||||
int n = (count + 7) / 8;
|
||||
|
||||
switch (count % 8)
|
||||
{
|
||||
case 0:
|
||||
do
|
||||
{
|
||||
*to++ = *from++;
|
||||
case 7:
|
||||
*to++ = *from++;
|
||||
case 6:
|
||||
*to++ = *from++;
|
||||
case 5:
|
||||
*to++ = *from++;
|
||||
case 4:
|
||||
*to++ = *from++;
|
||||
case 3:
|
||||
*to++ = *from++;
|
||||
case 2:
|
||||
*to++ = *from++;
|
||||
case 1:
|
||||
*to++ = *from++;
|
||||
} while (--n > 0);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int zeds_device(char *from, char *to, int count)
|
||||
{
|
||||
{
|
||||
int n = (count + 7) / 8;
|
||||
|
||||
switch (count % 8)
|
||||
{
|
||||
case 0:
|
||||
again: *to++ = *from++;
|
||||
|
||||
case 7:
|
||||
*to++ = *from++;
|
||||
case 6:
|
||||
*to++ = *from++;
|
||||
case 5:
|
||||
*to++ = *from++;
|
||||
case 4:
|
||||
*to++ = *from++;
|
||||
case 3:
|
||||
*to++ = *from++;
|
||||
case 2:
|
||||
*to++ = *from++;
|
||||
case 1:
|
||||
*to++ = *from++;
|
||||
if (--n > 0)
|
||||
{
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int valid_copy(char *data, int count, char expects)
|
||||
{
|
||||
int i = 0;
|
||||
for ( i = 0; i < count; ++i)
|
||||
{
|
||||
if (data[i] != expects)
|
||||
{
|
||||
log_err("[%d] %c != %c", i, data[i], expects);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char from[999] = { 'a' };
|
||||
char to[999] = { 'c' };
|
||||
int rc = 0;
|
||||
|
||||
// printf("%s", from);
|
||||
|
||||
// set up the from to have some stuff
|
||||
memset(from, 'x', 999);
|
||||
|
||||
|
||||
// set it to a failure mode
|
||||
memset(to, 'y', 999);
|
||||
check(valid_copy(to, 999, 'y'), "Not initialized right.");
|
||||
|
||||
// use normal copy to
|
||||
rc = normal_copy(from, to, 999);
|
||||
check(rc == 999, "Normal copy failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Normal copy failed.");
|
||||
|
||||
// reset
|
||||
memset(to, 'y', 999);
|
||||
|
||||
// duffs version
|
||||
rc = duffs_device(from, to, 999);
|
||||
check(rc == 999, "Duff's device failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Duff's device failed copy.");
|
||||
|
||||
// reset
|
||||
memset(to, 'y', 999);
|
||||
|
||||
// my version
|
||||
rc = zeds_device(from, to, 999);
|
||||
check(rc == 999, "Zed's device failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Zed's device failed copy.");
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return 1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,139 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dbg.h"
|
||||
|
||||
int normal_copy(char *from, char *to, int count)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
to[i] = from[i];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int duffs_device(char *from, char *to, int count)
|
||||
{
|
||||
{
|
||||
int n = (count + 7) / 8;
|
||||
|
||||
switch (count % 8)
|
||||
{
|
||||
case 0:
|
||||
do
|
||||
{
|
||||
*to = *from++;
|
||||
case 7:
|
||||
*to = *from++;
|
||||
case 6:
|
||||
*to = *from++;
|
||||
case 5:
|
||||
*to = *from++;
|
||||
case 4:
|
||||
*to = *from++;
|
||||
case 3:
|
||||
*to = *from++;
|
||||
case 2:
|
||||
*to = *from++;
|
||||
case 1:
|
||||
*to = *from++;
|
||||
} while (--n > 0);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int zeds_device(char *from, char *to, int count)
|
||||
{
|
||||
{
|
||||
int n = (count + 7) / 8;
|
||||
|
||||
switch (count % 8)
|
||||
{
|
||||
case 0:
|
||||
again: *to++ = *from++;
|
||||
|
||||
case 7:
|
||||
*to++ = *from++;
|
||||
case 6:
|
||||
*to++ = *from++;
|
||||
case 5:
|
||||
*to++ = *from++;
|
||||
case 4:
|
||||
*to++ = *from++;
|
||||
case 3:
|
||||
*to++ = *from++;
|
||||
case 2:
|
||||
*to++ = *from++;
|
||||
case 1:
|
||||
*to++ = *from++;
|
||||
if (--n > 0)
|
||||
{
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int valid_copy(char *data, int count, char expects)
|
||||
{
|
||||
int i = 0;
|
||||
for ( i = 0; i < count; ++i)
|
||||
{
|
||||
if (data[i] != expects)
|
||||
{
|
||||
log_err("[%d] %c != %c", i, data[i], expects);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char from[999] = { 'a' };
|
||||
char to[999] = { 'c' };
|
||||
int rc = 0;
|
||||
|
||||
// printf("%s", from);
|
||||
|
||||
// set up the from to have some stuff
|
||||
memset(from, 'x', 999);
|
||||
|
||||
|
||||
// set it to a failure mode
|
||||
memset(to, 'y', 999);
|
||||
check(valid_copy(to, 999, 'y'), "Not initialized right.");
|
||||
|
||||
// use normal copy to
|
||||
rc = normal_copy(from, to, 999);
|
||||
check(rc == 999, "Normal copy failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Normal copy failed.");
|
||||
|
||||
// reset
|
||||
memset(to, 'y', 999);
|
||||
|
||||
// duffs version
|
||||
rc = duffs_device(from, to, 999);
|
||||
check(rc == 999, "Duff's device failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Duff's device failed copy.");
|
||||
|
||||
// reset
|
||||
memset(to, 'y', 999);
|
||||
|
||||
// my version
|
||||
rc = zeds_device(from, to, 999);
|
||||
check(rc == 999, "Zed's device failed: %d", rc);
|
||||
check(valid_copy(to, 999, 'x'), "Zed's device failed copy.");
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define AREA(l, b) (l * b)
|
||||
|
||||
#define CASE_STATEMENT(n) case n: \
|
||||
*to++ = *from++;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("hello, world!%d\n", AREA(10, 5));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex24 test ex24_copy ex24_change
|
||||
|
||||
clean:
|
||||
rm -f ex24 test ex24_copy ex24_change
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define debug(M, ...)
|
||||
#else
|
||||
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
||||
|
||||
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define check_mem(A) check((A), "Out of memory.")
|
||||
|
||||
#define check_debug(A, M, ...) if(!(A)) {debug(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
#include <stdio.h>
|
||||
#include "dbg.h"
|
||||
|
||||
#define MAX_DATA 100
|
||||
|
||||
typedef enum EyeColor {
|
||||
BLUE_EYES, GREEN_EYES, BROWN_EYES,
|
||||
BLACK_EYES, OTHER_EYES
|
||||
} EyeColor;
|
||||
|
||||
const char *EYE_COLOR_NAMES[] = {
|
||||
"Blue", "Green", "Brown", "Black", "Other"
|
||||
};
|
||||
|
||||
typedef struct Person {
|
||||
int age;
|
||||
char first_name[MAX_DATA];
|
||||
char last_name[MAX_DATA];
|
||||
EyeColor eyes;
|
||||
double income;
|
||||
} Person;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Person you = { .age = 0 };
|
||||
int i = 0;
|
||||
char *in = NULL;
|
||||
|
||||
printf("What's your First Name? ");
|
||||
in = fgets(you.first_name, MAX_DATA - 1, stdin);
|
||||
// gets(you.first_name);
|
||||
check(in != NULL, "Failed to read first name.");
|
||||
// fscanf(stdin, "%50s", you.first_name);
|
||||
|
||||
printf("What's your Last Name? ");
|
||||
in = fgets(you.last_name, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read last name.");
|
||||
|
||||
printf("How old are you? ");
|
||||
|
||||
int rc = fscanf(stdin, "%d", &you.age);
|
||||
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
printf("What color are your eyes:\n");
|
||||
for (i = 0; i <= OTHER_EYES; ++i)
|
||||
{
|
||||
printf("%d %s\n", i + 1, EYE_COLOR_NAMES[i]);
|
||||
}
|
||||
printf("> ");
|
||||
|
||||
int eyes = -1;
|
||||
|
||||
rc = fscanf(stdin, "%d", &eyes);
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
you.eyes = eyes - 1;
|
||||
check(you.eyes <= OTHER_EYES
|
||||
&& you.eyes >= 0, "Do it right, that's not an option.");
|
||||
|
||||
printf("How much do you make an hour? ");
|
||||
rc = fscanf(stdin, "%lf", &you.income);
|
||||
check(rc > 0, "Enter a floating point number.");
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
|
||||
printf("First Name: %s", you.first_name);
|
||||
printf("Last Name: %s", you.last_name);
|
||||
printf("Age: %d\n", you.age);
|
||||
printf("Eyes: %s\n", EYE_COLOR_NAMES[you.eyes]);
|
||||
printf("Income: %f\n", you.income);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
|
||||
return -1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,90 @@
|
|||
#include <stdio.h>
|
||||
#include "dbg.h"
|
||||
|
||||
#define MAX_DATA 100
|
||||
|
||||
typedef enum EyeColor {
|
||||
BLUE_EYES, GREEN_EYES, BROWN_EYES,
|
||||
BLACK_EYES, OTHER_EYES
|
||||
} EyeColor;
|
||||
|
||||
const char *EYE_COLOR_NAMES[] = {
|
||||
"Blue", "Green", "Brown", "Black", "Other"
|
||||
};
|
||||
|
||||
typedef struct Person {
|
||||
int age;
|
||||
char first_name[MAX_DATA];
|
||||
char last_name[MAX_DATA];
|
||||
EyeColor eyes;
|
||||
double income;
|
||||
} Person;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Person you = { .age = 0 };
|
||||
int i = 0;
|
||||
char *in = NULL;
|
||||
int j = 0;
|
||||
|
||||
printf("What's your First Name? ");
|
||||
in = fgets(you.first_name, MAX_DATA - 1, stdin);
|
||||
// gets(you.first_name);
|
||||
check(in != NULL, "Failed to read first name.");
|
||||
|
||||
for (j = 0; you.first_name[j] != '\0'; ++j)
|
||||
{
|
||||
|
||||
}
|
||||
// printf("j:%d\n", j);
|
||||
you.first_name[j - 1] = '\0';
|
||||
// fscanf(stdin, "%50s", you.first_name);
|
||||
|
||||
printf("What's your Last Name? ");
|
||||
in = fgets(you.last_name, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read last name.");
|
||||
for (j = 0; you.last_name[j] != '\0'; ++j)
|
||||
{
|
||||
|
||||
}
|
||||
you.last_name[j - 1] = '\0';
|
||||
|
||||
printf("How old are you? ");
|
||||
|
||||
int rc = fscanf(stdin, "%d", &you.age);
|
||||
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
printf("What color are your eyes:\n");
|
||||
for (i = 0; i <= OTHER_EYES; ++i)
|
||||
{
|
||||
printf("%d %s\n", i + 1, EYE_COLOR_NAMES[i]);
|
||||
}
|
||||
printf("> ");
|
||||
|
||||
int eyes = -1;
|
||||
|
||||
rc = fscanf(stdin, "%d", &eyes);
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
you.eyes = eyes - 1;
|
||||
check(you.eyes <= OTHER_EYES
|
||||
&& you.eyes >= 0, "Do it right, that's not an option.");
|
||||
|
||||
printf("How much do you make an hour? ");
|
||||
rc = fscanf(stdin, "%lf", &you.income);
|
||||
check(rc > 0, "Enter a floating point number.");
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
|
||||
printf("First Name: %s", you.first_name);
|
||||
printf("Last Name: %s", you.last_name);
|
||||
printf("Age: %d\n", you.age);
|
||||
printf("Eyes: %s\n", EYE_COLOR_NAMES[you.eyes]);
|
||||
printf("Income: %f\n", you.income);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
|
||||
return -1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,92 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dbg.h"
|
||||
|
||||
#define MAX_DATA 100
|
||||
|
||||
typedef enum EyeColor {
|
||||
BLUE_EYES, GREEN_EYES, BROWN_EYES,
|
||||
BLACK_EYES, OTHER_EYES
|
||||
} EyeColor;
|
||||
|
||||
const char *EYE_COLOR_NAMES[] = {
|
||||
"Blue", "Green", "Brown", "Black", "Other"
|
||||
};
|
||||
|
||||
typedef struct Person {
|
||||
int age;
|
||||
char first_name[MAX_DATA];
|
||||
char last_name[MAX_DATA];
|
||||
EyeColor eyes;
|
||||
double income;
|
||||
} Person;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Person you = { .age = 0 };
|
||||
int i = 0;
|
||||
char *in = NULL;
|
||||
|
||||
char temp_age[MAX_DATA];
|
||||
char temp_eyes[MAX_DATA];
|
||||
char temp_income[MAX_DATA];
|
||||
|
||||
|
||||
printf("What's your First Name? ");
|
||||
in = fgets(you.first_name, MAX_DATA - 1, stdin);
|
||||
// gets(you.first_name);
|
||||
check(in != NULL, "Failed to read first name.");
|
||||
// fscanf(stdin, "%50s", you.first_name);
|
||||
|
||||
printf("What's your Last Name? ");
|
||||
in = fgets(you.last_name, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read last name.");
|
||||
|
||||
printf("How old are you? ");
|
||||
|
||||
in = fgets(temp_age, MAX_DATA - 1, stdin);
|
||||
you.age = atoi(temp_age);
|
||||
check(in != NULL, "Failed to read age.");
|
||||
// int rc = fscanf(stdin, "%d", &you.age);
|
||||
|
||||
// check(rc > 0, "You have to enter a number.");
|
||||
|
||||
printf("What color are your eyes:\n");
|
||||
for (i = 0; i <= OTHER_EYES; ++i)
|
||||
{
|
||||
printf("%d %s\n", i + 1, EYE_COLOR_NAMES[i]);
|
||||
}
|
||||
printf("> ");
|
||||
|
||||
int eyes = -1;
|
||||
|
||||
// rc = fscanf(stdin, "%d", &eyes);
|
||||
// check(rc > 0, "You have to enter a number.");
|
||||
in = fgets(temp_eyes, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read eyes.");
|
||||
eyes = atoi(temp_eyes);
|
||||
|
||||
you.eyes = eyes - 1;
|
||||
check(you.eyes <= OTHER_EYES
|
||||
&& you.eyes >= 0, "Do it right, that's not an option.");
|
||||
|
||||
printf("How much do you make an hour? ");
|
||||
// rc = fscanf(stdin, "%f", &you.income);
|
||||
// check(rc > 0, "Enter a floating point number.");
|
||||
in = fgets(temp_income, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read eyes.");
|
||||
you.income = atof(temp_income);
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
|
||||
printf("First Name: %s", you.first_name);
|
||||
printf("Last Name: %s", you.last_name);
|
||||
printf("Age: %d\n", you.age);
|
||||
printf("Eyes: %s\n", EYE_COLOR_NAMES[you.eyes]);
|
||||
printf("Income: %f\n", you.income);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
|
||||
return -1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
#include <stdio.h>
|
||||
#include "dbg.h"
|
||||
|
||||
#define MAX_DATA 100
|
||||
|
||||
typedef enum EyeColor {
|
||||
BLUE_EYES, GREEN_EYES, BROWN_EYES,
|
||||
BLACK_EYES, OTHER_EYES
|
||||
} EyeColor;
|
||||
|
||||
const char *EYE_COLOR_NAMES[] = {
|
||||
"Blue", "Green", "Brown", "Black", "Other"
|
||||
};
|
||||
|
||||
typedef struct Person {
|
||||
int age;
|
||||
char first_name[MAX_DATA];
|
||||
char last_name[MAX_DATA];
|
||||
EyeColor eyes;
|
||||
double income;
|
||||
} Person;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Person you = { .age = 0 };
|
||||
int i = 0;
|
||||
char *in = NULL;
|
||||
|
||||
printf("What's your First Name? ");
|
||||
in = fgets(you.first_name, MAX_DATA - 1, stdin);
|
||||
// gets(you.first_name);
|
||||
check(in != NULL, "Failed to read first name.");
|
||||
// fscanf(stdin, "%50s", you.first_name);
|
||||
|
||||
printf("What's your Last Name? ");
|
||||
in = fgets(you.last_name, MAX_DATA - 1, stdin);
|
||||
check(in != NULL, "Failed to read last name.");
|
||||
|
||||
printf("How old are you? ");
|
||||
|
||||
int rc = scanf("%d", &you.age);
|
||||
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
printf("What color are your eyes:\n");
|
||||
for (i = 0; i <= OTHER_EYES; ++i)
|
||||
{
|
||||
printf("%d %s\n", i + 1, EYE_COLOR_NAMES[i]);
|
||||
}
|
||||
printf("> ");
|
||||
|
||||
int eyes = -1;
|
||||
|
||||
rc = scanf("%d", &eyes);
|
||||
check(rc > 0, "You have to enter a number.");
|
||||
|
||||
you.eyes = eyes - 1;
|
||||
check(you.eyes <= OTHER_EYES
|
||||
&& you.eyes >= 0, "Do it right, that's not an option.");
|
||||
|
||||
printf("How much do you make an hour? ");
|
||||
rc = scanf("%lf", &you.income);
|
||||
check(rc > 0, "Enter a floating point number.");
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
|
||||
printf("First Name: %s", you.first_name);
|
||||
printf("Last Name: %s", you.last_name);
|
||||
printf("Age: %d\n", you.age);
|
||||
printf("Eyes: %s\n", EYE_COLOR_NAMES[you.eyes]);
|
||||
printf("Income: %f\n", you.income);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int ReadFile(const char* fname, int size, char name[], int arr_size)
|
||||
{
|
||||
int is_ok = EXIT_FAILURE;
|
||||
FILE* fp = fopen(fname, "w+");
|
||||
int i = 0;
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
perror("File opening failed");
|
||||
|
||||
return is_ok;
|
||||
}
|
||||
fputs("Boyang Wang\n", fp);
|
||||
rewind(fp);
|
||||
|
||||
// int c;
|
||||
int rc_scanf;
|
||||
|
||||
for (i = 0; (i < size - 1)&&(i < arr_size - 1); ++i)
|
||||
{
|
||||
// if ((c = fgetc(fp)) != EOF)
|
||||
// {
|
||||
// name[i] = c;
|
||||
// }
|
||||
|
||||
rc_scanf = fscanf(fp, "%c", &name[i]);
|
||||
if (0 == rc_scanf)
|
||||
{
|
||||
printf("rc_scanf=0\n");
|
||||
}
|
||||
|
||||
}
|
||||
name[i] = '\0';
|
||||
|
||||
if (ferror(fp))
|
||||
{
|
||||
puts("I/O error when reading");
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
puts("End of file is reached successfully");
|
||||
is_ok = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
remove(fname);
|
||||
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char* fname = "./hello.txt";
|
||||
int is_ok = EXIT_FAILURE;
|
||||
|
||||
FILE* fp = fopen(fname, "w+");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
perror("File opening failed");
|
||||
|
||||
return is_ok;
|
||||
}
|
||||
fputs("Hello, world!\n", fp);
|
||||
rewind(fp);
|
||||
|
||||
int c; // note: int, not char, required to handle EOF
|
||||
|
||||
while((c = fgetc(fp)) != EOF)
|
||||
{
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
if (ferror(fp))
|
||||
{
|
||||
puts("I/O error when reading");
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
puts("End of file is reached successfully");
|
||||
is_ok = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
remove(fname);
|
||||
|
||||
|
||||
char name[100];
|
||||
|
||||
ReadFile("./hello.txt", 12, name, 100);
|
||||
printf("name:%s\n", name);
|
||||
|
||||
return is_ok;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex25 ex25_copy myPrint simplePrint
|
||||
|
||||
clean:
|
||||
rm -f ex25 ex25_copy myPrint simplePrint
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ZED_DEBUG_MACRO(M, ...)
|
||||
#else
|
||||
#define ZED_DEBUG_MACRO(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ZED_CLEAN_ERRNO_MACRO() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define ZED_LOG_ERR_MACRO(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_WARN_MACRO(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_INFO_MACRO(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define ZED_CHECK_MACRO(A, M, ...) if(!(A)) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_SENTINEL_MACRO(M, ...) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_CHECK_MEM_MACRO(A) ZED_CHECK_MACRO((A), "Out of memory.")
|
||||
|
||||
#define ZED_CHECK_DEBUG_MACRO(A, M, ...) if(!(A)) {ZED_DEBUG_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,179 @@
|
|||
// WARNING:This code is freash and potentially isn't correct yet.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "dbg.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA_LENGTH_OF_STRING 100
|
||||
|
||||
int read_string(char **out_string, int max_buffer)
|
||||
{
|
||||
*out_string = calloc(1, max_buffer + 1);
|
||||
|
||||
|
||||
ZED_CHECK_MEM_MACRO(*out_string);
|
||||
// printf("hello_s");
|
||||
|
||||
char *result = fgets(*out_string, max_buffer, stdin);
|
||||
|
||||
ZED_CHECK_MACRO(result != NULL, "Input error.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (*out_string)
|
||||
{
|
||||
free(*out_string);
|
||||
}
|
||||
*out_string = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read_long(long *out_long)
|
||||
{
|
||||
char *input = NULL;
|
||||
// char *end = NULL;
|
||||
int rc = read_string(&input, MAX_DATA_LENGTH_OF_STRING);
|
||||
|
||||
// printf("hello_int");
|
||||
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read number.");
|
||||
|
||||
// *out_int = strtoi(input, &end, 10);
|
||||
// ZED_CHECK_MACRO(('\0' == *end || '\n' == *end) &&
|
||||
// *input != '\0', "Input number: %s", input);
|
||||
*out_long = atoi(input);
|
||||
// calloc set memery to zero, so we can check by testing if *input=='\0'
|
||||
ZED_CHECK_MACRO(*input != '\0', "Input number: %s", input);
|
||||
|
||||
free(input);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (input)
|
||||
{
|
||||
free(input);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read_scan(const char *fmt, ...)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
long *out_long = NULL;
|
||||
char *out_char = NULL;
|
||||
char **out_string = NULL;
|
||||
int max_buffer = 0;
|
||||
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
|
||||
for (i = 0; fmt[i] != '\0'; ++i)
|
||||
{
|
||||
if ('%' == fmt[i])
|
||||
{
|
||||
++i;
|
||||
switch (fmt[i])
|
||||
{
|
||||
case '\0':
|
||||
ZED_SENTINEL_MACRO("Invalid format, you ended with %%.");
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
out_long = va_arg(argp, long *);
|
||||
rc = read_long(out_long);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read long.");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
out_char = va_arg(argp, char *);
|
||||
*out_char = fgetc(stdin);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
max_buffer = va_arg(argp, int);
|
||||
out_string = va_arg(argp, char **);
|
||||
rc = read_string(out_string, max_buffer);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read string.");
|
||||
break;
|
||||
|
||||
default:
|
||||
ZED_SENTINEL_MACRO("Invalid format.");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fgetc(stdin);
|
||||
}
|
||||
|
||||
ZED_CHECK_MACRO(!feof(stdin) && !ferror(stdin), "Input error.");
|
||||
}
|
||||
|
||||
va_end(argp);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
va_end(argp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *first_name = NULL;
|
||||
char initial = ' ';
|
||||
char *last_name = NULL;
|
||||
long age = 0;
|
||||
|
||||
|
||||
|
||||
printf("What's your first name? ");
|
||||
|
||||
int rc = read_scan("%s", MAX_DATA_LENGTH_OF_STRING, &first_name);
|
||||
// int rc = read_scan("%s", &first_name);
|
||||
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed first name.");
|
||||
|
||||
|
||||
|
||||
printf("What's your initial? ");
|
||||
rc = read_scan("%c\n", &initial);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed initial.");
|
||||
|
||||
|
||||
|
||||
printf("What's your last name? ");
|
||||
rc = read_scan("%s", MAX_DATA_LENGTH_OF_STRING, &last_name);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed last name.");
|
||||
// printf("last_name: %s", last_name);
|
||||
|
||||
printf("How old are you? ");
|
||||
rc = read_scan("%d", &age);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read age.");
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
printf("First Name: %s", first_name);
|
||||
printf("Initial: '%c'\n", initial);
|
||||
printf("Last Name: %s", last_name);
|
||||
// printf("Age: %ld\n", age);
|
||||
printf("Age: %ld\n", age);
|
||||
|
||||
free(first_name);
|
||||
free(last_name);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,230 @@
|
|||
// WARNING:This code is freash and potentially isn't correct yet.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "dbg.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA_LENGTH_OF_STRING 100
|
||||
|
||||
int read_string(char **out_string, int max_buffer)
|
||||
{
|
||||
*out_string = calloc(1, max_buffer + 1);
|
||||
|
||||
|
||||
ZED_CHECK_MEM_MACRO(*out_string);
|
||||
// printf("hello_s");
|
||||
|
||||
// char *result = fgets(*out_string, max_buffer, stdin);
|
||||
int c;
|
||||
int count = 0;
|
||||
char *arr = *out_string;
|
||||
while (( c = fgetc(stdin)) != '\n')
|
||||
{
|
||||
arr[count] = c;
|
||||
// putchar(c);
|
||||
|
||||
++count;
|
||||
}
|
||||
// putchar('\n');
|
||||
|
||||
// ZED_CHECK_MACRO(result != NULL, "Input error.");
|
||||
ZED_CHECK_MACRO(*out_string != NULL, "Input error.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (*out_string)
|
||||
{
|
||||
free(*out_string);
|
||||
}
|
||||
*out_string = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read_long(long *out_long)
|
||||
{
|
||||
char *input = NULL;
|
||||
// char *end = NULL;
|
||||
int rc = read_string(&input, MAX_DATA_LENGTH_OF_STRING);
|
||||
|
||||
printf("hello_int");
|
||||
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read number.");
|
||||
|
||||
// *out_int = strtoi(input, &end, 10);
|
||||
// ZED_CHECK_MACRO(('\0' == *end || '\n' == *end) &&
|
||||
// *input != '\0', "Input number: %s", input);
|
||||
*out_long = atoi(input);
|
||||
// calloc set memery to zero, so we can check by testing if *input=='\0'
|
||||
ZED_CHECK_MACRO(*input != '\0', "Input number: %s", input);
|
||||
|
||||
free(input);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (input)
|
||||
{
|
||||
free(input);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read_scan(const char *fmt, ...)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
long *out_long = NULL;
|
||||
char *out_char = NULL;
|
||||
char **out_string = NULL;
|
||||
int max_buffer = 0;
|
||||
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
|
||||
for (i = 0; fmt[i] != '\0'; ++i)
|
||||
{
|
||||
if ('%' == fmt[i])
|
||||
{
|
||||
++i;
|
||||
switch (fmt[i])
|
||||
{
|
||||
case '\0':
|
||||
ZED_SENTINEL_MACRO("Invalid format, you ended with %%.");
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
out_long = va_arg(argp, long *);
|
||||
rc = read_long(out_long);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read long.");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
out_char = va_arg(argp, char *);
|
||||
*out_char = fgetc(stdin);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
max_buffer = va_arg(argp, int);
|
||||
out_string = va_arg(argp, char **);
|
||||
rc = read_string(out_string, max_buffer);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read string.");
|
||||
break;
|
||||
|
||||
default:
|
||||
ZED_SENTINEL_MACRO("Invalid format.");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fgetc(stdin);
|
||||
}
|
||||
|
||||
ZED_CHECK_MACRO(!feof(stdin) && !ferror(stdin), "Input error.");
|
||||
}
|
||||
|
||||
va_end(argp);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
va_end(argp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void simple_printf(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt == 'd') {
|
||||
int i = va_arg(args, int);
|
||||
printf("%d\n", i);
|
||||
} else if (*fmt == 'c') {
|
||||
// A 'char' variable will be promoted to 'int'
|
||||
// A character literal in C is already 'int' by itself
|
||||
int c = va_arg(args, int);
|
||||
printf("\'%c\'\n", c);
|
||||
} else if (*fmt == 'f') {
|
||||
double d = va_arg(args, double);
|
||||
printf("%f\n", d);
|
||||
} else if (*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
printf("%s\n", str);
|
||||
}
|
||||
|
||||
// printf("fmt:%c", *fmt);
|
||||
++fmt;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *first_name = NULL;
|
||||
char initial = ' ';
|
||||
char *last_name = NULL;
|
||||
long age = 0;
|
||||
|
||||
|
||||
|
||||
printf("What's your first name? ");
|
||||
|
||||
int rc = read_scan("%s", MAX_DATA_LENGTH_OF_STRING, &first_name);
|
||||
// int rc = read_scan("%s", &first_name);
|
||||
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed first name.");
|
||||
|
||||
|
||||
|
||||
printf("What's your initial? ");
|
||||
rc = read_scan("%c\n", &initial);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed initial.");
|
||||
|
||||
|
||||
|
||||
printf("What's your last name? ");
|
||||
rc = read_scan("%s", MAX_DATA_LENGTH_OF_STRING, &last_name);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed last name.");
|
||||
// printf("last_name: %s", last_name);
|
||||
|
||||
printf("How old are you? ");
|
||||
rc = read_scan("%d", &age);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to read age.");
|
||||
|
||||
printf("----- RESULTS -----\n");
|
||||
printf("First Name: %s", first_name);
|
||||
printf("Initial: '%c'\n", initial);
|
||||
printf("Last Name: %s", last_name);
|
||||
// printf("Age: %ld\n", age);
|
||||
printf("Age: %ld\n", age);
|
||||
|
||||
puts("----- RESULTS -----\n");
|
||||
puts("First Name: ");
|
||||
simple_printf("s", first_name);
|
||||
puts("Initial: ");
|
||||
simple_printf("c", initial);
|
||||
puts("Last Name: ");
|
||||
simple_printf("s", last_name);
|
||||
puts("Age: ");
|
||||
simple_printf("d", age);
|
||||
|
||||
free(first_name);
|
||||
free(last_name);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "dbg.h"
|
||||
|
||||
int MyPrint(const char *fmt, ...)
|
||||
{
|
||||
int i = 0;
|
||||
// int rc = 0;
|
||||
char out_char;
|
||||
// int max_buffer = 0;
|
||||
|
||||
puts("Hello");
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
|
||||
for (i = 0; fmt[i] != '\0'; ++i)
|
||||
{
|
||||
if ('%' == fmt[i])
|
||||
{
|
||||
++i;
|
||||
switch(fmt[i])
|
||||
{
|
||||
case 'c':
|
||||
out_char = va_arg(argp, int);
|
||||
putchar(out_char);
|
||||
break;
|
||||
|
||||
default:
|
||||
ZED_SENTINEL_MACRO("Invalid format.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fgetc(stdin);
|
||||
}
|
||||
|
||||
ZED_CHECK_MACRO(!feof(stdin) && !ferror(stdin), "Input error.");
|
||||
}
|
||||
|
||||
va_end(argp);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
va_end(argp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = MyPrint("%c\n", 'p');
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed initial");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void simple_printf(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt == 'd') {
|
||||
int i = va_arg(args, int);
|
||||
printf("%d\n", i);
|
||||
} else if (*fmt == 'c') {
|
||||
// A 'char' variable will be promoted to 'int'
|
||||
// A character literal in C is already 'int' by itself
|
||||
int c = va_arg(args, int);
|
||||
printf("%c\n", c);
|
||||
} else if (*fmt == 'f') {
|
||||
double d = va_arg(args, double);
|
||||
printf("%f\n", d);
|
||||
} else if (*fmt == 's') {
|
||||
char *str = va_arg(args, char*);
|
||||
printf("%s\n", str);
|
||||
}
|
||||
|
||||
// printf("fmt:%c", *fmt);
|
||||
++fmt;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
simple_printf("dcffs", 3, 'a', 1.999, 42.5, "helloC");
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex25
|
||||
|
||||
clean:
|
||||
rm -f ex26
|
Binary file not shown.
|
@ -0,0 +1,127 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// 打印出输入的参数
|
||||
if (1 == argc)
|
||||
{
|
||||
printf("You only have one argument. You suck.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Here's your arguments:\n");
|
||||
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
printf("%s ", argv[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// 从~/.logfind中加载允许访问的日志文件
|
||||
const char* fname = "/home/charles/.logfind";
|
||||
int is_ok = EXIT_FAILURE;
|
||||
|
||||
FILE* fp = fopen(fname, "w+");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
perror("File opening failed");
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
// 创建文件名列表
|
||||
fputs("Turing\n",fp);
|
||||
fputs("Turing1\n", fp);
|
||||
fputs("Turing2\n", fp);
|
||||
fputs("Turing9\n",fp);
|
||||
fputs("Neumann\n", fp);
|
||||
fputs("Church\n", fp);
|
||||
|
||||
rewind(fp);
|
||||
|
||||
// 读取文件,打印出匹配的行
|
||||
int index = 0;
|
||||
int is_same = 1; // 1表示匹配
|
||||
const int buf_size = 10; // 文件名最长为9个字符
|
||||
// char buf_get[buf_size] = argv[1]; // 存储读入的第二个字符串
|
||||
char buf_file[buf_size];
|
||||
|
||||
for (int j = 0; j < buf_size; ++j)
|
||||
{
|
||||
buf_file[j] = '\0';
|
||||
}
|
||||
|
||||
int c; // note: int, not char, required to handle EOF
|
||||
|
||||
index = 0;
|
||||
while (((c = fgetc(fp)) != EOF) ) // standard C I/O file reading loop
|
||||
{
|
||||
// putchar(argv[1][index]);
|
||||
// 存入当前行的内容,假设文件名中不包含换行符
|
||||
if (c != '\n') // 如果当前行的读取没有结束,则继续读入字符
|
||||
{
|
||||
buf_file[index] = c;
|
||||
}
|
||||
|
||||
// 对当前行进行处理
|
||||
if (1 == argc)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (2 == argc)
|
||||
{
|
||||
// 朴素模式串匹配,跳过了换行符和问号,包括了问号的功能
|
||||
if ((c != argv[1][index]) && (c != '\n') && ('?' != argv[1][index]))
|
||||
{
|
||||
is_same = 0;
|
||||
}
|
||||
// 一行结束
|
||||
if (c == '\n')
|
||||
{
|
||||
if ('?' == argv[1][index]) // 防止文件名末尾出现?时的错误匹配
|
||||
{
|
||||
is_same = 0;
|
||||
}
|
||||
// (1 == is_same)?puts(" ok"): puts(" no");
|
||||
if (1 == is_same) // 如果匹配
|
||||
{
|
||||
puts(buf_file);
|
||||
}
|
||||
// 变量重置
|
||||
index = -1; // index要等于-1,因为后面要++
|
||||
is_same = 1;
|
||||
for (int j = 0; j < buf_size; ++j)
|
||||
{
|
||||
buf_file[j] = '\0';
|
||||
}
|
||||
}
|
||||
// putchar(c);
|
||||
++index;
|
||||
}
|
||||
else if (argc > 2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// putchar('a');
|
||||
if (ferror(fp))
|
||||
{
|
||||
puts("I/O error when reading");
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
puts("End of file reached");
|
||||
is_ok = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
remove(fname);
|
||||
|
||||
return is_ok;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
hello, guys
|
|
@ -0,0 +1 @@
|
|||
you are smart
|
|
@ -0,0 +1 @@
|
|||
are you zedshaw
|
|
@ -0,0 +1 @@
|
|||
zedshaw is a smart guy
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall -g
|
||||
|
||||
all: ex25
|
||||
|
||||
clean:
|
||||
rm -f ex26
|
|
@ -0,0 +1,106 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// 打印出输入的参数
|
||||
if (1 == argc)
|
||||
{
|
||||
printf("You only have one argument. You suck.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Here's your arguments:\n");
|
||||
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
printf("%s ", argv[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// 从~/.logfind中加载允许访问的日志文件
|
||||
const char* fname = "/home/charles/.logfind";
|
||||
int is_ok = EXIT_FAILURE;
|
||||
|
||||
FILE* fp = fopen(fname, "w+");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
perror("File opening failed");
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
// 创建文件名列表
|
||||
fputs("Turing1\n", fp);
|
||||
fputs("Turing2\n", fp);
|
||||
fputs("Turing9\n",fp);
|
||||
fputs("Neumann\n", fp);
|
||||
fputs("Church\n", fp);
|
||||
|
||||
rewind(fp);
|
||||
|
||||
// 读取文件,打印出匹配的行
|
||||
int index = 0;
|
||||
int is_same = 1;
|
||||
const int buf_size = 10; // 文件名最长为9个字符
|
||||
// char buf_get[buf_size] = argv[1]; // 存储读入的第二个字符串
|
||||
char buf_file[buf_size];
|
||||
|
||||
for (int j = 0; j < buf_size; ++j)
|
||||
{
|
||||
buf_file[j] = '\0';
|
||||
}
|
||||
|
||||
|
||||
int c; // note: int, not char, required to handle EOF
|
||||
|
||||
index = 0;
|
||||
while ((c = fgetc(fp)) != EOF) // standard C I/O file reading loop
|
||||
{
|
||||
// putchar(argv[1][index]);
|
||||
buf_file[index] = c;
|
||||
// 朴素模式串匹配,跳过了换行符和问号,包括了问号的功能
|
||||
if ((c != argv[1][index]) && (c != '\n') && ('?' != argv[1][index]))
|
||||
{
|
||||
is_same = 0;
|
||||
}
|
||||
// 一行结束
|
||||
if (c == '\n')
|
||||
{
|
||||
// (1 == is_same)?puts(" ok"): puts(" no");
|
||||
if (1 == is_same)
|
||||
{
|
||||
puts(buf_file);
|
||||
}
|
||||
// 变量重置
|
||||
index = -1; // index要等于-1,因为后面要++
|
||||
is_same = 1;
|
||||
for (int j = 0; j < buf_size; ++j)
|
||||
{
|
||||
buf_file[j] = '\0';
|
||||
}
|
||||
}
|
||||
// putchar(c);
|
||||
++index;
|
||||
|
||||
}
|
||||
|
||||
// putchar('a');
|
||||
if (ferror(fp))
|
||||
{
|
||||
puts("I/O error when reading");
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
puts("End of file reached");
|
||||
is_ok = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
remove(fname);
|
||||
|
||||
return is_ok;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
hello, guys
|
|
@ -0,0 +1 @@
|
|||
you are smart
|
|
@ -0,0 +1 @@
|
|||
are you zedshaw
|
|
@ -0,0 +1 @@
|
|||
zedshaw is a smart guy
|
|
@ -0,0 +1,6 @@
|
|||
CFLAGS=-Wall
|
||||
|
||||
all: ex27_1
|
||||
|
||||
clean:
|
||||
rm -f ex27_1
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ZED_DEBUG_MACRO(M, ...)
|
||||
#else
|
||||
#define ZED_DEBUG_MACRO(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ZED_CLEAN_ERRNO_MACRO() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define ZED_LOG_ERR_MACRO(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_WARN_MACRO(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_INFO_MACRO(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define ZED_CHECK_MACRO(A, M, ...) if(!(A)) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_SENTINEL_MACRO(M, ...) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_CHECK_MEM(A) ZED_CHECK_MACRO((A), "Out of memory.")
|
||||
|
||||
#define ZED_CHECK_DEBUG_MACRO(A, M, ...) if(!(A)) {ZED_DEBUG_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,81 @@
|
|||
#undef NDEBUG
|
||||
#include "dbg.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Naive copy that assumes all inputs are always valid
|
||||
* taken from K&R C and cleaned up a bit.
|
||||
*/
|
||||
void copy(char to[], char from[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// while loop will not end if from isn't '\0' terminated
|
||||
while ((to[i] = from[i]) != '\0')
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A safer version that checks for many common errors using the
|
||||
* length of each string to control the loops and termination.
|
||||
*/
|
||||
int safercopy(int from_len, char *from, int to_len, char *to)
|
||||
{
|
||||
assert(from != NULL && to != NULL && "from and to can't be NULL");
|
||||
|
||||
int i = 0;
|
||||
int max = from_len > to_len - 1 ? to_len - 1 : from_len;
|
||||
|
||||
// to_len must have at least 1 byte
|
||||
if (from_len < 0 || to_len <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; ++i)
|
||||
{
|
||||
to[i] = from[i];
|
||||
}
|
||||
|
||||
to[to_len - 1] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// careful to understand why we can get these sizes
|
||||
char from[] = "0123456789";
|
||||
int from_len = sizeof(from);
|
||||
|
||||
// notice that it's 7 chars + \0
|
||||
char to[] = "0123456";
|
||||
int to_len = sizeof(to);
|
||||
|
||||
ZED_DEBUG_MACRO("Copying '%s':%d to '%s':%d", from, from_len, to, to_len);
|
||||
|
||||
int rc = safercopy(from_len, from, to_len, to);
|
||||
|
||||
ZED_CHECK_MACRO(rc > 0, "Failed to safercopy.");
|
||||
ZED_CHECK_MACRO('\0' == to[to_len - 1], "String not terminated.");
|
||||
|
||||
ZED_DEBUG_MACRO("Result is: '%s':%d", to, to_len);
|
||||
|
||||
// now try to break it
|
||||
rc = safercopy(from_len * -1, from, to_len, to);
|
||||
ZED_CHECK_MACRO(-1 != rc, "safercopy should fail #1");
|
||||
// printf("rc:%d", rc);
|
||||
ZED_CHECK_MACRO('\0' == to[to_len - 1], "String not terminated.");
|
||||
|
||||
rc = safercopy(from_len, from, 0, to);
|
||||
ZED_CHECK_MACRO(-1 == rc, "safercopy should fail #2");
|
||||
ZED_CHECK_MACRO('\0' == to[to_len - 1], "String not terminated.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
|
||||
LIBS=-ldl $(OPTLIBS)
|
||||
PREFIX?=/usr/local
|
||||
|
||||
SOURCES=$(wildcard src/**/*.c src/*.c)
|
||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||
|
||||
TEST_SRC=$(wildcard tests/*_tests.c)
|
||||
TESTS=$(patsubst %.c,%,$(TEST_SRC))
|
||||
|
||||
TARGET=build/libex29.a
|
||||
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
|
||||
|
||||
# The Target Build
|
||||
all: $(TARGET) $(SO_TARGET) tests
|
||||
|
||||
dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
|
||||
dev: all
|
||||
|
||||
$(TESTS): $(TARGET) $(SO_TARGET)
|
||||
|
||||
$(TARGET): CFLAGS += -fPIC
|
||||
$(TARGET): build $(OBJECTS)
|
||||
ar rcs $@ $(OBJECTS)
|
||||
ranlib $@
|
||||
$(SO_TARGET): $(TARGET) $(OBJECTS)
|
||||
$(CC) -shared -o $@ $(OBJECTS)
|
||||
|
||||
build:
|
||||
@mkdir -p build
|
||||
@mkdir -p bin
|
||||
|
||||
# The Unit Tests
|
||||
.PHONY: tests
|
||||
tests: CFLAGS += $(TARGET)
|
||||
tests: $(TESTS)
|
||||
sh ./tests/runtests.sh
|
||||
|
||||
# The Cleaner
|
||||
clean:
|
||||
rm -rf build $(OBJECTS) $(TESTS)
|
||||
rm -f tests/tests.log
|
||||
find . -name "*.gc*" -exec rm {} \;
|
||||
rm -rf 'find . -name "*.dSYM" -print'
|
||||
|
||||
# The Install
|
||||
install: all
|
||||
install -d $(DESTDIR)/$(PREFIX)/lib/
|
||||
indtall $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
|
||||
|
||||
# The Checker
|
||||
check:
|
||||
@echo Files with potentially dangerous functions.
|
||||
@egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ZED_DEBUG_MACRO(M, ...)
|
||||
#else
|
||||
#define ZED_DEBUG_MACRO(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ZED_CLEAN_ERRNO_MACRO() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define ZED_LOG_ERR_MACRO(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_WARN_MACRO(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_INFO_MACRO(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define ZED_CHECK_MACRO(A, M, ...) if(!(A)) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_SENTINEL_MACRO(M, ...) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_CHECK_MEM(A) ZED_CHECK_MACRO((A), "Out of memory.")
|
||||
|
||||
#define ZED_CHECK_DEBUG_MACRO(A, M, ...) if(!(A)) {ZED_DEBUG_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "dbg.h"
|
||||
|
||||
int print_a_message(const char *msg, int length)
|
||||
{
|
||||
printf("A STRING: %s\n", msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uppercase(const char *msg, int length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// BUG: \0 termination problems
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
printf("%c", toupper(msg[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lowercase(const char *msg, int length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// BUG: \0 termination problems
|
||||
for(i = 0; i < length; ++i)
|
||||
{
|
||||
printf("%c", tolower(msg[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail_on_purpose(const char *msg, int length)
|
||||
{
|
||||
return 1;
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
#include <stdio.h>
|
||||
#include "dbg.h"
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include "minunit.h"
|
||||
|
||||
typedef int (*lib_function) (const char *data, int length);
|
||||
|
||||
// 注意:需要传入lib_file和lib
|
||||
int check_function(const char *func_to_run, const char *data, int expected, char *lib_file, void *lib)
|
||||
{
|
||||
lib_function func = dlsym(lib, func_to_run);
|
||||
ZED_CHECK_MACRO(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror());
|
||||
|
||||
int length = strlen(data);
|
||||
int rc = func(data, length);
|
||||
ZED_CHECK_MACRO(expected == rc, "Function %s return %d for data: %s", func_to_run, rc, data);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *test()
|
||||
{
|
||||
char *lib_file = "build/libex29.so";
|
||||
|
||||
// printf("lib_file:%s", lib_file);
|
||||
|
||||
// test dlopen
|
||||
void *lib = dlopen(lib_file, RTLD_LAZY);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(lib == NULL, "Failed to open the library to test.");
|
||||
// test functions
|
||||
ZED_MU_ASSERT_MACRO(check_function("print_a_message", "Hello, Boyang", 0, lib_file, lib), "print_a_message failed.");
|
||||
ZED_MU_ASSERT_MACRO(check_function("uppercase", "hello, Boyang", 0, lib_file, lib), "uppercase failed.");
|
||||
ZED_MU_ASSERT_MACRO(check_function("lowercase", "hello, Boyang", 0, lib_file, lib), "lowercase failed.");
|
||||
// test failures
|
||||
ZED_MU_ASSERT_MACRO(check_function("fail_on_purpose", "Hello", 1, lib_file, lib), "fail_on_purpose should fail.");
|
||||
|
||||
// test dlclose
|
||||
int rc = dlclose(lib);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(0 != rc, "Failed to close lib.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *all_tests()
|
||||
{
|
||||
ZED_MU_SUITE_START_MACRO();
|
||||
|
||||
ZED_MU_RUN_TEST(test);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZED_RUN_TESTS_MACRO(all_tests);
|
|
@ -0,0 +1,33 @@
|
|||
#undef NDEBUG
|
||||
#ifndef _minunit_h
|
||||
#define _minunit_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dbg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ZED_MU_SUITE_START_MACRO() char *message = NULL
|
||||
|
||||
#define ZED_MU_ASSERT_MACRO(test, message) if (test) {\
|
||||
ZED_LOG_ERR_MACRO(message); return message; }
|
||||
|
||||
#define ZED_MU_RUN_TEST(test) ZED_DEBUG_MACRO("\n-----%s", " " #test); \
|
||||
message = test(); ++tests_run; if (message) return message;
|
||||
|
||||
#define ZED_RUN_TESTS_MACRO(name) int main(int argc, char *argv[]) {\
|
||||
ZED_DEBUG_MACRO("----- RUNNING: %s", argv[0]); \
|
||||
printf("----\nRUNNING: %s\n", argv[0]); \
|
||||
char *result = name(); \
|
||||
if (result != 0) { \
|
||||
printf("FAILED: %s\n", result); \
|
||||
} \
|
||||
else { \
|
||||
printf("ALL TESTS PASSED\n"); \
|
||||
} \
|
||||
printf("Tests run: %d\n", tests_run); \
|
||||
exit(result != 0); \
|
||||
}
|
||||
|
||||
int tests_run;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
echo "Running unit tests:"
|
||||
|
||||
for i in tests/*_tests
|
||||
do
|
||||
if test -f $i
|
||||
then
|
||||
if $VALGRIND ./$i 2>> tests/tests.log
|
||||
then
|
||||
echo $1 PASS
|
||||
else
|
||||
echo "ERROR in test $i: here's tests/tests.log"
|
||||
echo "------"
|
||||
tail tests/tests.log
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ZED_DEBUG_MACRO(M, ...)
|
||||
#else
|
||||
#define ZED_DEBUG_MACRO(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ZED_CLEAN_ERRNO_MACRO() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
#define ZED_LOG_ERR_MACRO(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_WARN_MACRO(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
#define ZED_LOG_INFO_MACRO(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define ZED_CHECK_MACRO(A, M, ...) if(!(A)) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_SENTINEL_MACRO(M, ...) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#define ZED_CHECK_MEM(A) ZED_CHECK_MACRO((A), "Out of memory.")
|
||||
|
||||
#define ZED_CHECK_DEBUG_MACRO(A, M, ...) if(!(A)) {ZED_DEBUG_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#include <stdio.h>
|
||||
#include "dbg.h"
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef int (*lib_function) (const char *data, int length);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
ZED_CHECK_MACRO(4 == argc, "USAGE: ex29 libex29.so function data");
|
||||
|
||||
char *lib_file = argv[1];
|
||||
char *func_to_run = argv[2];
|
||||
char *data = argv[3];
|
||||
|
||||
int length = strlen(argv[3]);
|
||||
|
||||
void *lib = dlopen(lib_file, RTLD_NOW);
|
||||
|
||||
ZED_CHECK_MACRO(lib != NULL, "Failed to open the library %s: %s", lib_file, dlerror());
|
||||
|
||||
lib_function func = dlsym(lib, func_to_run);
|
||||
ZED_CHECK_MACRO(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror());
|
||||
|
||||
rc = func(data, length);
|
||||
ZED_CHECK_MACRO(0 == rc, "Function %s return %d for data: %s", func_to_run, rc, data);
|
||||
|
||||
rc = dlclose(lib);
|
||||
ZED_CHECK_MACRO(0 == rc, "Failed to close %s", lib_file);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "dbg.h"
|
||||
|
||||
int print_a_message(const char *msg, int length)
|
||||
{
|
||||
printf("A STRING: %s\n", msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uppercase(const char *msg, int length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// BUG: \0 termination problems
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
printf("%c", toupper(msg[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lowercase(const char *msg, int length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// BUG: \0 termination problems
|
||||
for(i = 0; i < length; ++i)
|
||||
{
|
||||
printf("%c", tolower(msg[i]));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail_on_purpose(const char *msg, int length)
|
||||
{
|
||||
return 1;
|
||||
}
|
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue