C语言—扫盲补充

22

1. 内存管理:

void *calloc(int num , int size)——在内存中动态的分配num个长度为 size的连续空间,并初始化为0

void *malloc(int num)——在堆区分配一块指定大小的内存空间,内存空间未初始化,值是未知的

void *realloc(void *address,int newsize)——重新分配内存,并把内存扩展到newsize

void free(void * address)—— 释放address指向的内存块,释放动态分配的内存

2. C的作用域规则

—局部变量:在函数或块内部——栈中,只在调用时分配内存

—全局变量:在所有函数外边——静态存储

—形式参数:在函数的参数定义中

当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。

3. 枚举

enum  枚举名 {元素1,元素2......};

enum DAY{ MON=1, TUE, WED, THU, FRI, SAT, SUN};  // 每个元素都可以赋值,后面的元素值,如果没有赋值,则为前面元素值加一

枚举看起来比宏定义更简洁

#define MON 1

#define TUE  2

...

#define SUN 7

注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

4. 函数指针

函数指针是指向函数的指针变量,

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

#include  

int max(int x, int y)

{ return x > y ? x : y;} 

int main(void){ 

     /* p 是函数指针 */ 

     int (* p)(int, int) = & max; // &可以省略 int a, b, c, d;

    printf("请输入三个数字:");

    scanf("%d %d %d", & a, & b, & c);

    /* 与直接调用函数等价,d = max(max(a, b), c) */   

    d = p(p(a, b), c);

    printf("最大的数字是: %d\n", d);

    return 0;

}

回调函数:函数指针作为某个函数的参数。

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

简单讲:回调函数是由别人的函数执行时调用你实现的函数。

5. 关于size_t

size_t 是一种数据类型,近似于无符号整型,但容量范围一般大于 int 和 unsigned。

但凡不涉及负值范围的表示size取值的,都可以用size_t;比如array[size_t]。

size_t 在stddef.h头文件中定义。

在其他常见的宏定义以及函数中常用到有:

1,sizeof运算符返回的结果是size_t类型;

2,void *malloc(size_t size)...

类似的还有wchar_t, ptrdiff_t。

wchar_t就是wide char type,“一种用来记录一个宽字符的数据类型”。

ptrdiff_t就是pointer difference type,“一种用来记录两个指针之间的距离的数据类型”。

通常,size_t和ptrdiff_t都是用typedef来实现的。你可能在某个头文件里面找到类似的语句:

typedef unsigned int size_t;


6. 错误处理

C 语言不提供对错误处理的直接支持,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。

所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。开发人员应该在程序初始化时,把 errno 设置为 0,这是一种良好的编程习惯。0 值表示程序中没有错误。

c语言提供了perror()和strerror()函数来显示与errno相关的文本消息。

perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。

strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。 

perror()用于实时显示,strerror用于存储,便于后续调试。

7. 递归问题

C 语言支持递归,即一个函数可以调用其自身。但在使用递归时,程序员需要注意定义一个从函数退出的条件,否则会进入死循环。

递归函数在解决许多数学问题上起了至关重要的作用,比如计算一个数的阶乘、生成斐波那契数列,等等。

递归是一个简洁的概念,同时也是一种很有用的手段。但是,使用递归是要付出代价的。与直接的语句(如while循环)相比,递归函数会耗费更多的运行时间,并且要占用大量的栈空间。递归函数每次调用自身时,都需要把它的状态存到栈中,以便在它调用完自身后,程序可以返回到它原来的状态。未经精心设计的递归函数总是会带来麻烦。

采用递归方法来解决问题,必须符合以下三个条件:

1、可以把要解决的问题转化为一个新问题,而这个新的问题的解决方法仍与原来的解决方法相同,只是所处理的对象有规律地递增或递减。说明:解决问题的方法相同,调用函数的参数每次不同(有规律的递增或递减),如果没有规律也就不能适用递归调用。

2、可以应用这个转化过程使问题得到解决。说明:使用其他的办法比较麻烦或很难解决,而使用递归的方法可以很好地解决问题。

3、必定要有一个明确的结束递归的条件。说明:一定要能够在适当的地方结束递归调用。不然可能导致系统崩溃。


8. 命令行参数

执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。

命令行参数是使用 main() 函数参数来处理的,其中,

argc 是指传入参数的个数

argv[] 是一个指针数组,指向传递给程序的每个参数

应当指出的是,argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,*argv[n] 是最后一个参数。如果没有提供任何参数,argc 将为 1,否则,如果传递了一个参数,argc 将被设置为 2。

多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 "" 或单引号 '' 内部。让我们重新编写上面的实例,有一个空间,那么你可以通过这样的观点,把它们放在双引号或单引号""""。让我们重新编写上面的实例,向程序传递一个放置在双引号内部的命令行参数:

$./a.out "testing1 testing2"


9. assert 用法

编写代码时,我们总是会做出一些假设,assert就是用于在代码中捕捉这些假设。

C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息。

#define assert(ignore) ((void)0)

10.  signal.h

【Linux函数】Signal ()函数详细介绍 - 华秋实的专栏 - CSDN博客

signal.h是C标准函数库中的信号处理部分, 定义了程序执行时如何处理不同的信号。信号用作进程间通信, 报告异常行为(如除零)、用户的一些按键组合(如同时按下Ctrl与C键,产生信号SIGINT)。

signal:

void (*signal(int sig, void (*handler)(int)))(int);

SIG_ 宏与 signal 函数一起使用来定义信号的功能

1SIG_DFL  默认的信号处理程序。

2SIG_ERR  表示一个信号错误。

3SIG_IGN  忽视信号

signal()用于确定以后当信号sig出现时的处理方法。如果handler的值是SIG_DFL,那么就采用实现定义的缺省行为;如果handler的值是SIG_IGN,那么就忽略该信号;否则,调用handler所指向的函数(参数为信号类型)。有效的信号包括:

SIGABRT异常终止,如调用abort()。

SIGFPE算术运算出错,如除数为0或溢出。

SIGILL非法函数映象,如非法指令。

SIGINT交互式信号,如中断。

SIGSEGV非法访问存储器,如访问不存在的内存单元。

SIGTERM发送给本程序的终止请求信号。

raise:

#include

int raise(int sig);

向程序发送信号sig。如果发送不成功,就返回一个非0值。


11. 输入输出函数

int getchar(void): 从屏幕读取下一个可用的字符,并把它返回为一个整数。

int putchar  (void )  : 函数把字符输出到屏幕上,并返回相同的字符。

    int c;

  printf( "Enter a value :");

  c = getchar( );

  printf( "\nYou entered: ");

  putchar( c );

  printf( "\n");


char *gets(char *s) : 函数从stdin读取亿航到s所指向的缓冲区,直到一个终止符或EOF

char *fgets(char *s, int n, FILE *stream);//可以这么使用fgets(str, sizeof(str), stdin)  

——fgets函数功能:从文件指针stream中读取字符,存到以s为起始地址的空间里,直到读完N-1个字符,或者读完一行。

int puts(const char*s) : 函数把字符串s和一个尾随的换行符写入到stdout

注意:gets函数由于没有指定输入字符大小,所以会无限读取,一旦输入的字符大于数组长度,就会发生内存越界,从而造成程序崩溃或其他数据的错误。另外linux下不支持gets 和 puts,需要使用fgets 和fputs

char str[100];

  printf( "Enter a value :");

  gets( str );

  printf( "\nYou entered: ");

  puts( str );


int    scanf(const char *format,...)//函数从标准输入流stdin读取输入,并根据提供的format来浏览输入

int    printf(const char *format,...)// 函数把输出写入到标准输出流 stdout,并根据提供的格式产生输出。

char str[100];

int i;

printf( "Enter a value :");

scanf("%s %d", str, &i);

printf( "\nYou entered: %s %d ", str, i);

printf("\n");


常见错误问题:

学 C 语言的时候,字符输入曾经困扰过我,例如这段代码:

int i; char c;

scanf("%d%c", &i,&c);

这时候变量 c 中存储的往往不是你想输入的字符,而是一个空格,然后我们又会这样来写:

int i;char c;

scanf("%d", &i);scanf("%c", &c);

这时候,我们发现,根本没有输入字符C的机会,这是为什么?因为输入流是有缓冲区的,我们输入的字符存储在那,然后再赋值给我们的变量。我们可以这样改:

int i;char c;scanf("%d", &i);while((c=getchar())==' ' || c=='\n');c = getchar();

这个办法是一直读取,读到没有空格和换行就跳出循环,但是有一个更好的解决办法;

int i;char c;

scanf("%d%[^' '^'\n']", &i, &c);

这是用正则表达来控制输入格式为非空格非换行。

注意:在使用标准输入函数,需要通过stdin输入时候,请注意 空格和 回车换行的问题。此时正则表达式是一个很好的解决问题的方式。

你可能感兴趣的:(C语言—扫盲补充)