编写一个函数,实现字符串的拷贝,不允许利用库函数 strcpy()
使用strcpy的原型 man strcpy
char *tstycpy ( char *dest , const char*src)
功能:完成字符串的拷贝,将src指定内存中的内容拷贝到dest指定的内存中
参数:dest目标地址 src源地址
1) 为什么返回值是char*?
因为需要知道目标地址?可以通过dest知道目标地址
strlen(strcpy(dest,”tang”));
strcpy(dest1,strcpy(dest,”qiao”));
char * 是为了函数的嵌套调用 (留一手)
2) 为什么dest前边没有const,而src前面需要const?
因为src指定的地址的内存中的内容不能修改,而dest指定的地址的内容可以更改。
1#include<stdio.h>
2char *tstrcpy(char *dest,const char *src);
3int main(void){
4 charname[20]="tang";
5 char name1[20],name2[20];
6 tstrcpy(name2,tstrcpy(name1,name));
7 printf("name1=%s\nname2=%s\n",name1,name2);
8 return 0;
9 }
10char *tstrcpy(char *dest,const char *src){
11 int i=0;
12 while(src[i]!='\0'){
13 dest[i]=src[i];
14 i++;
15 }
16 dest[i]='\0';
17 return dest;
18 }
方法二:
1#include<stdio.h>
2char *tstrcpy(char *dest,const char *src);
3int main(void){
4 charname[20]="tang";
5 char name1[20];
6 tstrcpy(name1,name);
7 printf("name1=%s\n",name1);
8 return 0;
9 }
10char *tstrcpy(char *dest,const char *src){
11 char *p_str=dest;
12 while((*(dest++)=*(src++))!='\0'){
13 }
14 *dest='\0';
15 return p_str;
16 }
学好C语言的三要素
(1) 常量和变量的区别
(2) 变量的访问方式 : 先通过变量的名字找到变量的地址,然后根据类型读取变量的内容(什么是数据类型?数据类型的本质就是数据的访问方式,一次访问几个字节)
(3) 运算符的优先级及其结合性
今天内容:
一、 大型项目开发的文件组织
软件工程:
第一:熟悉客户的业务
第二:提取客户的需求,需求描述书
第三:需求分析
第四:系统设计
第五:编码
第六:测试
第七:交付
第八:后期技术支持
接口要规定好
头文件:头文件内容:
1) 头文件卫士
2) 函数的声明
3) 类型的定义(结构体typedef)
typedef的使用
typedef int Count ;
Count i ; i 是什么类型? int
typedef int(*fun_t)(int,int);
fun_t f ; f是什么类型?
typedef三步走:
第一步:int Count: 先定义类型的变量,区分出谁是变量,谁是类型
第二步:typedefint Count ; 加上typedef,原来的变量就变为类型的别名。
第三步:Count i ; 用别名定义一个变量。 i是 int 类型
Char *str ; str 是变量 *是类型 str里面放地址,存字符类型的地址 char是指针访问一个字节
int a=3;
str=&a;会有警告
typedef char *str;
str p1,p2; p1 p2是指针型变量
int ( *math_t ) ( int , int ); 定义了函数指针
int *math_t ( int ,int ); 定义返回值为指针的函数
int *p;定义一个指针变量,一次访问4(int)个字节
int *p[3];定义一个数组,数组里的每一个成员都是指针类型,
int ( *p )[3] ; 数组指针 p是一个指针类型的变量,除了(*p)都是访问方式,3个int为一个基本访问单位,一次访问3*int =12个字节
int **p ;
typedef int ( *math_t ) ( int , int );
math_t 指针类型;本质就是 int ( * ) ( int ,int )
int ( *p ) ( int , int );定义了一个变量,变量名是p,指针类型的,访问方式int ( int , int )
math_t p; 相当于 int ( *p ) ( int , int );
二维数组本质是一维数组,只是分成几个单位,每个单位是一个小的一位数组
计算机内存存放字节地址分两种:小端和大端
低字节放到高地址 ( 大端) 和低字节放到低地址(小端)。 PC用小端,网络用大端。
4) 宏定义
5) 变量的声明
变量的定义和变量的声明:
变量的定义是为变量分配空间的,变量的声明不需要分配空间
若在一个文件里已经定义过int var_i ; 变量的定义
在另一个文件里只需声明extern int var_i 变量的声明
第一步:写头文件tmath.h
第二步:实现文件tmath.c
第三步:写含有main函数的测试代码
第四步:对每个.c源文件进行单独的编译,编译成.o文件
第五步:对多个.o文件进行链接,形成可执行文件
nm 二进制文件的名字
-T 函数的实现在本文件中
-U 在本文件中使用了这个函数,但是这个函数的代码在本文件中不存在
tarena@tarena-virtual-machine:~/day22$ nmtmath.o
00000000 T add
0000002a T div
0000001e T mul
0000000d T sub
tarena@tarena-virtual-machine:~/day22$ nmtest.o
U add
U div
00000000 T main
U mul
U printf
U sub
tarena@tarena-virtual-machine:~/day22$ gcctmath.o test.o
tarena@tarena-virtual-machine:~/day22$ nm ./a.out
080483f4 T add
0804841e T div
08048430 T main
08048412 T mul
U printf@@GLIBC_2.0
08048401 T sub
tarena@tarena-virtual-machine:~/day22$ gcc-v test.o tmath.o
(gcc –v test.o tmath.o :-v参数就是将程序从 .o文件到可执行文件的这个编译过程全部显示在屏幕上)
tarena@tarena-virtual-machine:~/day22$nm/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o
00000000 R _IO_stdin_used
00000000 D __data_start
U __libc_csu_fini
U __libc_csu_init
U __libc_start_main
00000000 R _fp_hw
00000000 T _start
00000000 W data_start
U main
(main也是被系统调用,一起链接)
链接的原理:此时发生在编译阶段的链接是静态链接,T和U结合
(以上说的编译阶段是指大的编译阶段,即.c文件到a.out之间的阶段)
跟运行时库文件进行链接,形成可执行文件
tarena@tarena-virtual-machine:~/day22$ nma.out
080483f4 T main
08048506 T mul
U printf@@GLIBC_2.0
080484f5 T sub
此时printf 还没有使用
动态链接:将代码加载到内存以后进行链接,又成为延迟绑定。
PS:程序在运行时才把动态库的printf函数加载进来,即执行a.out时,进行链接。
静态库:函数库,库中存放的是.o文件,这些文件发生在静态链接阶段。
动态库:库文件中存放的也是.o文件,但是和这些函数的链接发生在加载到内存以后。
静态链接和动态链接的区别:
静态链接发生在编译阶段,是将代码的实现拷贝到函数的调用位置,所以静态链接的文件比较大。可执行文件不依赖于库文件
动态链接发生在加载到内存以后,文件比较小。但是可执行文件必须依赖于库文件。
ldd 可执行文件 作用:查看可执行文件依赖于哪些动态库文件。
tarena@tarena-virtual-machine:~/day22$ ldda.out
linux-gate.so.1=> (0xb7781000)
libc.so.6=> /lib/i386-linux-gnu/libc.so.6 (0xb75c3000)
/lib/ld-linux.so.2(0xb7782000)
二、gdb调试工具
第一步:在编译的时候,加-g或-ggdb参数
gcc test.c tmath.c –g
第二步:gdb 可执行文件名
gdb a.out
gdb命令:
l list
b main 在main函数处设置断电
b 函数的名字或者是数字(行号)
断点 函数执行到断点就停下来
r 是run 继续运行
n 是下一步
p 变量名 printf这个变量的内容
s step 一步一步的意思,单步执行
q 退出调试工具
作业:用gdb命令跟踪:
1、void swap(int x,int y)
2、void swap(int *x,int *y)
3、数组作为函数的形参
三、静态库的制作和使用