Linux C 学习笔记 十三

数据结构

 

数组

struct Element

{

//…………

};

struct Eelement *create(size_t len);

 

int add(struct Element,struct Element e);

 

int del(struct Elements,size_t index);

 

outAll(struct Elements);

 

void desttory(struct Element);

 

 

队列

 

struct Node

{

Element e;

struct Node *next;

}

create

destroy

enqueue

dequeue

size

iterate //遍历

front //查看

 

Node:结点,数据结构中用与保存数据的单元。

 

栈结构 stack

 

push:亚栈

pop:弹栈

 

 

create()

destroy()

size()

top()

iterate()

 

 

 

链表list

create()

destroy()

insert()

delete()

size()

iterate()

ARRAY

array.h

#ifndef __ARRAY_H
#define __ARRAY_H
#include “element.h”

typedef struct array
{
Element *eHead;
size_t max_size;
size_t counter;
}Array;

//创建并初始化数据
Array *create(size_t len);
//销毁数据
void destroy(Array *arr);
//增加数组元素
ssize_t add(Array *arr,Element e);
//删除数组元素
ssize_t del(Array *arr,size_t index);
//输出数组信息
void out(Array *arr);

//
ssize_t size(Array *arr);
ssize_t update(Array *arr,size_t index,Element e);

#endif

element.h

#ifndef __ELEMENT_H__
#define __ELEMENT_H__
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<memory.h>
typedef struct employee
{

char name[20];
int age;
float salary;
}Element;

 

#endif

array.c

#include”array.h”
#define INIT_MAX_SIZE 5
//创建并初始化数据
Array *create(size_t len)
{
Array *arr = (Array *)malloc(sizeof(Array));
assert(arr != NULL);
memset(arr,0,sizeof(Array));

Element *eHead =
(Element *)malloc(len*sizeof(Element));
assert(eHead != NULL);
memset(eHead,0,len*sizeof(Element));

arr->eHead = eHead;
arr->max_size = len;
return arr;
}
//销毁数据
void destroy(Array *arr)
{
assert(arr != NULL);
if(arr->eHead != NULL)
free(arr->eHead);

free(arr);//不会修改arr = NULL 不会修改函数外的指针
arr = NULL;
}
//增加数组元素
ssize_t add(Array *arr,Element e)
{

assert(arr != NULL);
if(arr->counter >= arr->max_size)
{
Element *eNew = (Element *)
realloc(arr->eHead,(arr->max_size+1)*sizeof(Element));
if(eNew == NULL)
return -1;
arr->eHead = eNew;
arr->max_size++;
}
//添加数组元素
*(arr->eHead+arr->counter) = e;
arr->counter++;
return 0;
}
//删除数组元素
ssize_t del(Array *arr,size_t index)
{
assert(arr != NULL);
//越界
if(index >= arr->counter)
return -1;
int i;
//移动数组,填补空隙
for(i =index;i < arr->counter;i++)
{
*(arr->eHead+i) = *(arr->eHead+i+1);
}
arr->counter–;
return 0;
}

static void out_element(Element *e)
{
printf(“=============Element info=================\n”);
printf(“Name:%s “,e->name);
printf(“Age:%d “,e->age);
printf(“Salary:%f\n “,e->salary);
printf(“\n”);
}

//输出数组u信息
void out(Array *arr)
{
assert(arr != NULL);
int i;
for(i = 0;i<arr->counter;i++)
{
printf(“===%d===”,i);
out_element(arr->eHead+i);
}
}

array_test.c

#include”element.h”
#include”array.h”
int main(void)
{

Array *arr = create(2);
Element e1 = {“Zhangsan”,22,10000.0};
Element e2 = {“Lisi”,23,8000.0};
Element e3 = {“wangwu”,33,99999.0};

add(arr,e1);
add(arr,e2);
out(arr);

 

return 0;
}

 LIST

list.h

#ifndef __LIST_H__
#define __LIST_H__

#include”element.h”
typedef struct node Node;
struct node
{
Element *e;
Node *next;
};

Node *create();
void destroy(Node *head);
void insert(Node *head,Element *e);
void delete(Node *head,Element *e);
Node *find(Node *head,Element *e);
int size(Node *head);
void iterate(Node *head);

#endif

element.h

#ifndef __ELEMENT_H__
#define __ELEMENT_H__
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<memory.h>
typedef struct employee
{

int id;
char name[20];
int age;
float salary;
}Element;
void out_element(Element *e);
Element *make_element(Element *e,int id,char *name,int age,float salary);
#endif

element.c

#include”element.h”
void out_element(Element *e)
{
printf(“\n==========Element info===============\n”);
printf(“ID:%d “,e->id);
printf(“Name:%s “,e->name);
printf(“Age:%d “,e->age);
printf(“Salary:%.2f”,e->salary);
printf(“\n”);
}

Element *make_element(Element *e,int id,char *name,int age,float salary)
{
assert(e != NULL);
e->id = id;
strcpy(e->name,name);
e->age = age;
e->salary = salary;
return e;
}

list.c

#include”list.h”

/*
* 创建链表
*/
Node *create()
{
Node *head = (Node *)malloc(sizeof(Node));
assert(head != NULL);
memset(head,0,sizeof(Node));

return head;
}

/*
* 销毁链表
*/
void destroy(Node *head)
{
if(head == NULL)
return ;
destroy(head->next);
free(head);
printf(“freed: %p\n”,head);
}

/*
* 向链表中插入元素
*/
void insert(Node *head,Element *e)
{
assert(head != NULL);

//创建新的节点
Node *pNew = (Node *)malloc(sizeof(Node));
assert(pNew != NULL);
memset(pNew,0,sizeof(Node));

pNew->e = e;

Node *pPre = head;
Node *pCur = head->next;

while(pCur != NULL)
{
if(pCur->e->id >= e->id)//找到元素合适的插入位置
break;

//指针后移
pPre = pPre->next;
pCur = pCur->next;
}
//查找一个和合适的插入位置

pNew->next = pCur;
pPre->next = pNew;
}

/*
* 删除链表中某个元素的节点
*/
void delete(Node *head,Element *e)
{
assert(head != NULL);
Node *pCur = head->next;
Node *pPre = head;
while(pCur != NULL)
{
if(pCur->e->id == e->id)//找到了合适的插入位置
break;
pPre = pPre->next;
pCur = pCur->next;
}

//空链表,或者未找到
if(pCur == NULL)
return ;
//删除

pPre->next = pCur->next;
free(pCur);
}

/*
* 查找包含某个元素的节点
*/
Node *find(Node *head,Element *e)
{
assert(head != NULL);
Node *pCur = head->next;
while(pCur != NULL)
{
if(pCur->e->id == e->id)
break;
pCur = pCur->next;
}
return pCur;
}

/*
* 返回链表的长度
*/
int size(Node *head)
{
assert(head != NULL);
int counter = 0;
Node *pCur = head->next;
while(pCur != NULL)
{
pCur = pCur->next;
counter++;
}
return counter;
}

/*
* 遍历链表
*/
void iterate(Node *head)
{
assert(head != NULL);
Node *pCur = head->next;
while(pCur != NULL)
{
out_element(pCur->e);
pCur = pCur->next;
}

//if(head == NULL)
//return;
//iteratr(head->next);
//if(head->e != NULL)
//out_element(head->e);
}

list_test.c 

#include “list.h”
int main(void)
{

Node *list = create();
Element *e1 = (Element *)malloc(sizeof(Element));
Element *e2 = (Element *)malloc(sizeof(Element));
Element *e3 = (Element *)malloc(sizeof(Element));

make_element(e1,1,”Zhangsan”,22,10000.0);
make_element(e2,2,”Lisi”,33,999999.0);
make_element(e3,3,”wangwu”,44,8888.0);

insert(list,e1);
insert(list,e2);
insert(list,e3);

iterate(list);

printf(“%d\n”,size(list));
printf(“============================\n”);

out_element(find(list,e2)->e);

delete(list,e2);
delete(list,e3);

printf(“%d\n”,size(list));
destroy(list);

free(e1);
free(e2);
free(e3);

return 0;
}

Linux C 学习笔记 十二

 

高级指针

int f //整形变量

int *f //整形指针变量

int *f,g

int f() //返回int的函数

int *f() //返回int *的函数

int (*f)() //返回int函数指针

int f[] //int 数组

int *f[] //int*元素数组,也就是指针数组?

Int (*f[])() //返回int函数指针数组

int *(*f[])() //返回int *函数指针数组

 

 

 

函数指针

指向函数存放地址的指针

* &对其无影响,既不修改内容,也不修改偏移量。

默认偏移量为1

对函数指针进行算数运算+ – ,不能偏移至其它函数的地址

 

转移表

 

基本计算器的实现

#include<stdio.h>
#include<assert.h>

double add(double x,double y)
{
return x+y;
}
double sub(double x,double y)
{
return x-y;
}
double div(double x,double y)
{
assert(y != 0);
return x/y;

}
double mul(double x,double y)
{
return x*y;
}

//函数指针数组
double (*opFun[])(double,double) =
{
add,sub,mul,div
};

char ops[] =
{
‘+’,’-‘,’*’,’/’
};

double oper(double x,double y,double(*opFun)(double,double))
{
return opFun(x,y);
}

int main(void)
{
double x=0,y=0,ret;
char op=’\0′;

printf(“Please input your exp:”);
scanf(“%lf%c%lf”,&x,&op,&y);
int i;
int len = sizeof(ops)/sizeof(ops[0]);
for(i=0;i<len;i++)
{
if(ops[i] == op)
{
//命中匹配的运算符
ret = oper(x,y,opFun[i]);
break;
}
}
if(i == len)
{
printf(“Unkown operator\n”);
exit(1);
}

printf(“Done: %lf %c %lf = %f\n”,x,op,y,ret);
return 0;
}

 

fun_funp.c

#include<stdio.h>

int fun1()
{
printf(“by fun1\n”);
}

int fun2()
{
printf(“by fun2\n”);
}
void out_fun(void (*fp)(),int n)
{
printf(“n:%d\n”,n);
fp();//这种形式呢就称为回调过程callback
}

int main(void)
{

out_fun(fun1,100);

return 0;
}

 

funp.c

#include<stdio.h>

int fun1(int n)
{
printf(“n in fun1:%d\n”,n);
return 1;
}
int fun2(int n)
{
printf(“n in fun2:%d\n”,n);
return 2;
}

 

int main(void)
{

int (*fp)(int); //函数指针
fp = fun1;
fp = &fun1;
fp = *fun1;
//fun(100);
fp(200);
(*fp)(200);

printf(“fun1:%p\n”,fun1);
printf(“fun1:%p\n”,*fun1);
printf(“&fun1:%p\n”,fp);

printf(“fun1:%p\n”,fun1+1);
printf(“fun1:%p\n”,*fun1+1);
printf(“&fun1:%p\n”,fp+1);
return 0;
}

max.c

#include<stdio.h>

struct employee
{

char name[20];
int age;
float salary;
}Employee;

typedef struct employee Employee

Employee *getMax(Employee emps[],int len,int (*comp)(Employee *,Employee *))
{
int i;
Employee *max_emp = emps;
for(i =0;i<len;i++)
{
if(comp(emps+i,max_emp)>0)
max_emp = emps+i;
}
return max_emp;
}

void out_emp(Employee *e)
{
printf(“—-Employee info——-\n”);
printf(“Name:%s “e->name);
printf(“Age:%d “e->age);
printf(“Salary:%.2f “e->salary);
printf(“\n”);
}

int comp_name(Employee *e1,Employee *e2)
{
return strcmp(e1->name,e2->name);
}
int comp_age(Employee *e1,Employee *e2)
{
return e1->age – e2->age;
}
int comp_salary(Employee *e1,Employee *e2)
{
if(e1->salary – e2->salary > 0)
return 1;
else
return -1;
}

int main(void)
{
Employee emps[] =
{
{“Zhangsan”,22,23232.2},
{“Lisi”,11,890098.3},
{“Wangwu”,44,5465.5}
};

int len = sizeof(emps)/sizeof(emps[0]);
out_emp(getMax(emps,len,comp_name));
return 0;
}

 

Linux C 学习笔记 十一

动态内存分配

stack

局部变量

函数执行(压栈、弹栈)

code 代码区(只能读,不能修改)

函数代码

字符串常量,所有双引号包裹的字符串

data 数据区

全局变量

静态变量(static修饰)

heap 堆区

 

动态内存分配

在程序中按照需要和在需要时分配内存的方式叫做动态分配内存,动态内存在堆上分配。

 

size_t 等同于当前平台的unsigned int

ssize_t ——————–> signed int

 

申请与释放

申请

malloc()

calloc()

realloc()

释放

free()

 

void *malloc(size_t size);

允许从空闲内存池中分配连续内存

size 参数是一个所需字节数的整数;

返回一个只想void类型的指针,在使用时要根据需要做强制类型转换

 

void *calloc(size_t num_elements,size_t element_size);

分配的内存被初始化为0

num_element:所需元素的数量

element_size:每个元素的字节数

 

void *realloc(void *ptr,size_t new_size);

必须是已经申请到了的内存,new_size 是表示新的内存的大小,而不是说你想要增加或者减少的值的多少。

ptr指向的内存基础上扩大或者缩小内存。

 

 

Void free(void *pointer)

 

 

 

api中说malloc是不会初始化的,但是实际上在程序运行时程序一开始时会初始化一下

 

malloc calloc的区别在于,calloc 申请后会初始化一下为0

 

 

 

//初始化

memset(p,0,sizeof(int));//清空工作,p指向刚刚申请的空间,0表示设置的值

//设置多长呢?就是sizeof(int)

 

 

在内存分配上realloc 如果还有足够的空间扩张,则其继续扩张,不够则在新的地址空间开辟一块,然后复制过去,然后释放原来旧的空间。扩张的时候不会释放。

 

 

free(void *pointer);

释放的指针必须是通过申请得到的,然后释放。

如果你不释放,到程序结束时,操作系统内核也会检测,但是建议程序员自己释放。

malloc calloc 一次必须释放一次。

 

 

 

常见错误

段错误:编译器不能自动发现发生内存错误,通常是在程序运行时才能捕捉到。没有明显的错误,时隐时现。

 

第一种错误:

内存分配不成功,却使用了它:编程新手常犯这种错误,因为没有意识到内存分配会不成功,常用解决办法,在使用内存之前检查指针是否为NULL

如果是用malloccallocrealloc来申请内存,应该用ifp == NULL)或ifp != NULL)进行防错处理。

即使有时候我们有剩余足够的空间,但由于有时候我们申请的空间过大,可能没有连续的足够大到我们申请的空间时,这时候也会申请失败。

 

也可以使用断言判断申请内存是否成功

#include<assert.h>//断言

//使用断言进行判断

//断言满足条件则程序继续执行,否之中断推出

p = NULL;

assert(p != NULL);

 

printf(“p:%p\n”,p);

 

第二种错误:

内存分配成功,但是尚未初始化就引用了它:一是没有初始化观念,二是误以为内存的缺省初始值玩全为零,导致引用初值错误。

所以无论用何种当时创建数组,都别忘了赋初值,即便是赋零值也不可以省略,不要嫌麻烦。

 

 

第三中错误:内存分配成功并且已经初始化,但操作越过了内存的边界。

如循环和递归的次数越界。

 

第四中错误:忘记了释放内存,造成内存泄漏。

含有这种错误的函数每次被调用一次就丢失一块内存,刚开始时系统的内存充足,你看不到错误,终有一次程序突然死掉,系统出现提示:内存耗尽。

动态内存的申请与释放必须配对,程序中mallocfree的使用次数一定要相同,否则肯定有错误(newdelete同理)。

Int *p = (int *)malloc(sizeof(int));

p = (int *)malloc(10*sizeof(int));

free(p);

这样第一次申请的第一块内存就找不见了。释放只是释放第二次申请到的。应该操作完之后就记得free一次;当然释放两次也是不行的,这时可能会告诉你double free() 程序崩溃。

建议在一个文件内申请的就在文件内释放,在模块申请的不要传递出去。

 

第五种错误:释放了内存却继续使用它

释放内存后变量内容不改变,依然会保留上一次使用的地址。释放后继续使用此内存属于非法访问

最好将已经释放的指针变量指空。

定义了指针没有赋值就变成了野指针,或者是释放了内存后继续使用指针也为野指针。

指针变量没有初始化。指针pfree或者delete之后,没有置为NULL,让人误以为p是个合法的指针,这两种都是野指针。

指针消亡了,并不表示它所指的内存会被自动释放。比如把指针指向其它的地方

内存被释放了,并不表示指针会消亡或者成了NULL指针

 

数据结构

以某种规则来定义数据存储的方式,使得数据单元和数据单元之间产生联系性。

#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
void print_memory(int *start,int len)
{
int *p = start;
for(;p<start+len;p++)
{
printf(“%p—–>%d\n”,p,*p);
}

}

int main(void)
{

int *p =(int *)malloc(10*sizeof(int));
//初始化
memset(p,0,sizeof(int));//清空工作,p指向刚刚申请的空间,0表示设置的值
//设置多长呢?就是sizeof(int)

printf(“p:%p\n”,p);
print_memory(p,10);

printf(“\n”);

/*
int counter =0;

int *p = NULL;
int *q = (int *)malloc(sizeof(int));
*q = 100;

//while(!*((int *)malloc(4)))
while(p = (int *)malloc(sizeof(int)))
{
if(!p)
break;
if(*p == 0)
{ counter++;
// printf(“.”);
// fflush(stdout);
// printf(“\n%p\n”,p);
}
else
{
printf(“*”);
fflush(stdout);
}
}
free(q);
printf(“%d\n”,counter);
*/

int *pc = (int *)calloc(10,sizeof(int));
*pc =100;
print_memory(pc,10);
printf(“===================\n”);
pc = (int *)realloc(pc,20*sizeof(int));
print_memory(pc,20);

return 0;
}

Linux C 学习笔记 十

递归

递归与循环的异同

都能用来完成一个反复的过程。

循环:每次反复都执行同一个过程。更适合运算结果/

递归:每次反复都以上一层结果作为依托。更适合描述算法。

栈空间开销大。

 

结构体和联合

. 表示用结构提变量访问。

-> 表示用结构体指针访问

 

结构体进行函数调用时,建议使用传值调用。输出可以使用传值,但是输入必须传地址。

 

成员本身又属于一个结构体则需要使用若干成员运算符,一级一级地找到最低一级的成员。

结构体变量成员可以像普通变量一样进行各种相应的运算。

可以引用结构体变量成员的地址,也可以引用结构体变量的地址。

 

 

可以将一个结构体放入另外一个结构体,”但结构体不能嵌套它自身,指针例外”

 

 

struct student stu3;//结构体之间赋值,逐项复制。

//若结构体内带有指针类型,不推荐

//会导致2个结构体变量内的指针指向同一个内存地址

print_StuInfo(stu);

stu3 = stu;//结构体间逐项赋值

 

让一个指针指向结构体,则其指向的是结构体的第一个成员的地址,也是结构体的地址。

 

结构体的三种引用形式

结构体变量名.成员名

(*p.成员名

p->成员名

 

结构体的存储分配

struct align1

{

char a;//4

itn b;//4

char c;//4

}

//12字节

 

struct align2

{

int b;//4

char a;

char c;

//和起来占4

}

 

原因因为:内存地址字对齐,CPU一次读取固定长度

 

位段:

与结构类似,每个成员是一个或多个位的字段

所有成员实际存储于一个或多个整形变量中。

说明:

位段成员必须声明为int,signed int,unsigned int

每个成员名后面是冒号和长度(位长)

位段的移植能力较弱

在位段中先声明为低位,后声明为高位。

 

#include<stdio.h>

 

struct CHAR

{

unsigned a:8;

unsigned b:12;

unsigned c:12;;

};

int main(void)

{

unsigned int i;

 

struct CHAR *p=(struct CHAR*)&i;

p->a = 0b11111111;

p->b = 0;

p->c = 0b111111111111;

 

printf(“i:%x\n”,i);

return 0;

}

 

 

 

联合

所有成员引用的是内存中相同的位置

联合的长度是它最长成员的长度

联合变量初始化必须是联合的地一个成员类型。

联合体在使用时,同一时刻只能作为其成员的某一个类型来处理。因为在其内部所有成员共享同一段内存空间。

 

数据存放从地位开始按字节顺序存放。

 

#include <stdio.h>
#include <stdlib.h>

typedef unsigned int uint32;

/*
* gcc -std=c99 -o bin/net1 src/net1.c
*/
int main(void)
{
uint32 ipAddr[4];
uint32 maskAddr[4];
uint32 netAddr[4];
uint32 ip32 = 0;
uint32 mask32 = 0;
uint32 net32 = 0;
int prefix;

printf(“Enter IP address <x.y.z.t>: “);
scanf(“%d.%d.%d.%d”,
&ipAddr[3],&ipAddr[2],&ipAddr[1],&ipAddr[0]);

printf(“Enter prefix: “);
scanf(“%d”,&prefix);

// 192.168.1.200
//将IP地址转换为32位计算机地址
//
//0000,0000 0000,0000 0000,0000 0000,0000
//0000,0000 0000,0000 0000,0000 200
//0000,0000 0000,0000 1 0000,0000
//0000,0000 0000,0000 1 200
//0000,0000 0000,0000 0000,0000 168
//
//000000000000000000000000 192
//0000000000 192 168
//0000000 192 168 0000,0000
//
//192 168 1 0000,0000
for(int i = 3; i >= 0; i–)
ip32 = ip32 << 8 | ipAddr[i];
// 24
//创建32位mask
//24
//111100000000000000000000000000000
//11111111111111110000,0000
//111111111111111111111111111111111
//0001 0000000000000000000000000000 28
//0010 0000000000000000000000000000 29
//0100 0000000000000000000000000000 30
//1000 0000000000000000000000000000 31
for(int i = 32 – prefix; i < 32; i++)
mask32 = mask32 | (1 << i);

//AND获取32位网络地址
net32 = ip32 & mask32;

//192.168.45.111
//将32位mask转换为 x.y.z.t
for(int i = 0; i < 4; i++){
maskAddr[i] = mask32 & 0b11111111;
mask32 = mask32 >> 8;
}

//将32位IP地址转换为 x.y.z.t
for(int i = 0; i < 4; i++){
netAddr[i] = net32 % 256;
net32 = net32 / 256;
}

//1234 –> % 10 4
// 1234 / 10 –> 123

printf(“\nAddress:\n”);
printf(“IP Address:\t%d.%d.%d.%d\n”,
ipAddr[3],ipAddr[2],ipAddr[1],ipAddr[0]);
printf(“Mask Address:\t%d.%d.%d.%d\n”,
maskAddr[3],maskAddr[2],maskAddr[1],maskAddr[0]);
printf(“Net Address:\t%d.%d.%d.%d\n”,
netAddr[3],netAddr[2],netAddr[1],netAddr[0]);

return 0;
}

Linux C 学习笔记 九

函数结构

 

/*

*函数说明

*/

类型说明符 函数名(形参列表)

参数说明

 

形式参数:在定义函数时,函数名后面括号中的变量名称为形式参数

实际参数:在函数调用时,函数名后面括号中的表达式称为实际参数

函数的返回值决定于函数定义时的返回类型。

在被定义的函数中必须执行函数的行参类型。

声明 :int fun(参数列表);参数列表的变量名可以不写,但要写出类型。

定义 :

int fun(参数列表)

函数的实现。。。。

 

 

传值调用

int swap(int x,int y);

swap(a,b);

 

传址调用

int swap(int *x,int *y);

swap(&a,&b);

 

只需要取值来进行运算取得结果时,使用传值调用

需要对于原数据进行诙谐的情况,使用传址调用

 

使用指针作为函数参数传递即为传址调用是错误的说法。

 

void swap_(int *x,int *y) //可能会发生溢出

{

*x = *x + *y;

*y = *x – *y;//x ===>y

*x = *x-*y;//y >===x;

}

void swap_3(int *x,int *y) 推荐使用

{ //x:1010 y:0101

*x = *x ^ *y;

*y = *x ^ *Y;

*x = *x ^ *y;

}

swap_2(int *x,int *y) 可能会有溢出,不能等于0

{ //x:10 y:2

x* = *x * *y ;

y=*x/*y;

*x=*x/*y;

 

}

 

 

函数说明(声明):包括函数名,函数类型,和函数参数类型,可不指定行参名。

 

在函数调用中

#include<stdio.h>

int fun1(int n)

{

return n;

}

int fun2(int n)

{

// printf(“in fun2()\n”);

}

int main(void)

{

int res1 = fun1(100);

int res2 = fun2(100);

 

printf(“res1:%d\n”,res1);

printf(“res2:%d\n”,res2);

 

return 0;

}

 

当注释掉printf(fun2)这句时,输出为100100,打印的res原本的fun1return 寄存器的结果,

当不注视时,输出为100 10,而这里打印的是fun2调用printfprintfreturn 寄存器的结果,也就是printf打印的字符总数。

 

返回过程中,首先将返回结果保存至return 寄存器,永远不会被清空,都是覆盖。

不使用return 语句,返回结果为最后一次使用return 寄存器的结果。

 

在设计函数的时候记得主调调被调这样的过程越少越好。因为栈空间会越来越深。—-注意考虑递归过程

 

ADT和黑盒

 

黑盒测试分类:

正确性

可用性

边界检查

性能测试: 3s以下是比较好的,3-5s是可以接受的,>5s用户就要来找你!

压力测试

兼容性测试

网络安全

 

完整性?

方法:穷举法,

 

白盒测试

从源代码入手,每个逻辑分支都必须测试,每个分支都运行至少一边,检查算法,溢出,优化等等问题。

ADT:抽象数据类型(abstract data type):用于描述生活中的一些抽象的数据类型

 

 

 

问题一:

Char *strcpy() char* strcpy()有什么区别 ——没区别

char *deschar* src又有什么区别 ——没区别

 

问题二:

char *str1=”hello”

char *str2=NULL; ——一定要给指针一段空间才可以赋值。指向为空是不能赋值的。

*str2++ = *str1++

 

递归:函数直接或者间接的调用自己。

递归出口

递归过程

 

1 9 10 11 12 13 20