首页 > 代码库 > C语言随笔记(一)

C语言随笔记(一)

自己把一些学习中和使用中的一些点滴有用的记录下来和大家分享。

 

1.获取指定长度的字符串,或者说为字符串数组获取用户输入的字符
void get_str(char str[], int len)
{
int i=0, c;
while (i<len)
{
c = getchar();/*这里是防止开始之前用户输入过回车,我们就跳过不处理*/
if (c == ‘\n‘)
{
if (!i)
continue;
str[i] = ‘\0‘;
break;
}
str[i++] = c;
}
if (i == len)
{
if (c != ‘\n‘)
while (getchar() != ‘\n‘)
;
str[i] = ‘\0‘;
}
}
使用举例:
char str[11];//结尾保存’\0’
get_str(str,sizeof(str)-1);
或者使用如下格式
#define NAME_CUT 50
char name[NAME_CUT+1];
get_str(str,NAME_CUT);

添加双引号的宏
#define F(x) _F(x)
#define _F(x) #x
使用举例:
在这种场景下
#define NAME_CUT 50
char name[NAME_CUT+1]
我们需要打印name,就可以写成
printf(“%” F(NAME_CUT) ”s\n”,name);
当然真如果出现这种情况,我推荐使用如下宏
#define CUT_FORMAT(x) _CUT_FORMAT(x)
#define _CUT_FORMAT(x) “%”#x”s”
使用就改为
printf(CUT_FORMAT(NAME_CUT) “\n”,name);

推荐的链表的声明格式
typedef
struct node
{
......
}
NODE;/*数据类型*/
typedef
struct list
{
NODE data;
struct NODE *next;
}
LIST;/*链表类型*/
使用举例
#define NUM_CUT 10 /*数据中编号最大长度*/
#define NAME_CUT 20 /*数据中姓名最大字符数*/
typedef
struct
{
char num[NUM_CUT + 1];
char name[NAME_CUT + 1];
char sex;
char age;
}
STU;/*数据类型*/
typedef
struct NODE
{
STU data;
struct NODE *next;
}
LIST;/*链表类型*/
这种写法非常漂亮,容易扩展

简单的malloc宏,添加了’日志’记录
#define MALLOC(mp) \
{\
if (NULL == (mp = malloc(sizeof(*mp)))) \
{\
fputs("内存分配失败,程序退出......", stderr);\
exit(EXIT_FAILURE); \
}\
}
使用举例
假设存在如下环境
#define NUM_CUT 10 /*数据中编号最大长度*/
#define NAME_CUT 20 /*数据中姓名最大字符数*/
typedef
struct
{
char num[NUM_CUT + 1];
char name[NAME_CUT + 1];
char sex;
char age;
}
STU;/*数据类型*/
STU *stu;
那么为stu开辟一个空间只需要添加下面的宏语句.
MALLOC(stu);//显然它也存在一个C关于malloc的通病,就是内存不足时,再打印文本也是无法执行的.但是它的原意是日志记录,虽然不一定会记录成功.
再扩展一下MALLOC如下:
#define MALLOC(var) if(!(var=malloc(sizeof(*var)))){\
fputs("内存申请失败,程序退出中...\n",stderr);\
exit(EXIT_FAILURE);\
}
文件打开的简单宏,添加了’日志’记录
#define FOPEN(file,path,type) \
{\
if (NULL == (file = fopen(path, type)))\
{\
fputs("内存不足程序退出中", stderr);\
exit(EXIT_SUCCESS);\
}\
}
举例
FILE *file;
FOPEN(file,”work_log.rec”,”rb”);

在控制台上清除输入缓存
while (getchar() != ‘\n‘)
;
举例
譬如存在如下语句
int c,num;
printf(“请输入一个整数:”);
scanf(“%d”,&num);
printf(“请再输入一个字符:”);
c=getcahr();
在上面的scanf和getchar之间就存在输入缓存问题,默认getchar()接收的值为’\n’.
这样c获取的值不是我们事先预估的
解决办法就是在二者之间加上
While(getchar()!=’\n’)
  ;
扩展一下,更加严格的应该是这段代码
int ch;
While((ch=getchar())!=EOF&&ch!=’\n’)
  ;
上面的情况是允许用户使用退出getchar()的操作,getchar这个函数在接收错误的时候返回-1,其实就是EOF文件结束标志宏.在window上可以按下Ctrl+Z,Linux上可以按下Ctrl+D达到让getchar函数返回-1的效果,结束当前的输入.
在这里,我采用的设计思路是,要么关闭当前程序,要么就必须输入完整.关键看程序员的想法吧!

关于scanf函数获取用户输入值的一种简便用法
while (printf(......)
,scanf(......)!=......||......)
{
while (getchar() != ‘\n‘)
;
puts(......);
}
举例
例如存在如下要求,需要接收用户输入的一个数,这个数必须小于250,大于0
代码如下:
int num;
while(printf(“请输入一个大于0小于250的整数:”),
  scanf(“%d”,&num)!=1||num<=0||num>=250)
{
  while(getchar()!=’\n’)
  ;
puts(“输入错误,请按照提示重新操作!”);
}
当然有时嫌它代码重复,可以定义如下简单宏
#define CLEAR while (getchar() != ‘\n‘)/*清除缓存*/
#define CLEARANDMSG {CLEAR;puts("输入出错,请按照提示重新操作!");}
使用的话就可以写成
int num;
while(printf(“请输入一个大于0小于250的整数:”),
  scanf(“%d”,&num)!=1||num<=0||num>=250)
CLEARANDMSG;
但是上面的代码很丑,关键看自己怎么看了.

关于printf输出格式串%*的用法
#define NAME_CUT 50
char name[NAME_CUT+1];
printf("%*s\n",NAME_CUT,name);
举例
对于这个技巧,是为了避免一些错误,例如如果name数组中没有’\0’,输出采用%s则会使输出内容不可控.还有一点就是它也统一控制了姓名打印对齐的格式.

比较古老的关于结构体空间声明技巧
typedef
struct node
{
int num;
char name[];
}
NODE;
举例
上面是C99定义包含空数组的结构体,在比较老的时候还存在
typedef
  struct node
  {
  int num;
  char name[1];
  }
NODE;
typedef
  struct node
  {
  int num;
  char name[0];
  }
NODE;
上面两种模式,思路都一致.声明的时候可以写成
int n=10;
NODE node=malloc(sizeof(NODE)+n);
达到可变数组的目的.(注结构体中 char name[]和char *name,是不同的)

高级简单一点的FOPEN宏的实现
#define FOPEN(file,path,type) \
FILE *##file;\
if (NULL == (##file = fopen(path, type)))\
{\
fputs("内存不足程序退出中", stderr);\
exit(EXIT_SUCCESS);\
}
举例
如果想将worker_one.rec文件内容复制到worker_two.rec文件中,
创建并打开文件对象的代码就是:
FOPEN(worker_one_file,”worker_one.rec”,”rb”);
FOPEN(worker_two_file,”worker_one.rec”,”wb”);
详细完整的代码如下:
FOPEN(wo_file,”worker_one.rec”,”rb”);
FOPEN(wt_file,”worker_one.rec”,”wb”);
for(int c;(c=fgetc(wo_file))!=EOF;fputc(c,wt_file))
  ;
fclose(wo_file);
fclose(wt_file);