前言

C标准库源码可通过下列两个网站进行查看:The GNU C LibraryWelcome to uClibc-ng! - Embedded C library

以下学习记录也是以这两个网站提供的库函数源码进行学习的。

字符串相关

strcpy()函数

头文件:#include <string.h>

函数原型:char *strcpy(char *dest, const char *src);

函数描述:将src指向的字符串拷贝到dest,包括结束符'\0'。字符串不能重叠,并且dest有足够的空间接收拷贝的字符串。

返回值:返回指向dest存放字符串的指针。

函数原型:

char *strcpy(char *dest, const char *src)
{
char *dst = dest; while ((*dst = *src) != '\0') {
src++;
dst++;
} return dest;
}

可以看出,函数中并不会检查dest的空间大小,只会拷贝字符串直到遇到src字符串的结束符'\0',因此dest的空间大小需要用户保证。

测试用例一:dest空间大于src指向的字符串个数。

#include <stdio.h>
#include <string.h> int main(void)
{
char *str_original = "0123456789";
char buf_dest[12] = {0};
char *ret = NULL;
int i = 0; for (i = 0; i < sizeof(buf_dest); i++)
buf_dest[i] = 1; printf("dest:0x%x\n", buf_dest);
ret = strcpy(buf_dest, str_original);
printf(" ret:0x%x\n", ret);
for (i = 0; i < sizeof(buf_dest); i++)
printf("%d ", buf_dest[i]);
printf("\n"); return 0;
}

编译,运行结果:

$ ./a.out
dest:0xca8e26c0
ret:0xca8e26c0
48 49 50 51 52 53 54 55 56 57 0 1

可以看出,字符串拷贝的时候会拷贝字符串结束符'\0'。

测试用例二:dest空间小于src指向的字符串个数(错误用法)。

#include <stdio.h>
#include <string.h> int main(void)
{
char *str_original = "0123456789";
char buf_dest[5] = {0};
char *ret = NULL;
int i = 0; for (i = 0; i < sizeof(buf_dest); i++)
buf_dest[i] = 1; printf("dest:0x%x\n", buf_dest);
ret = strcpy(buf_dest, str_original);
printf(" ret:0x%x\n", ret);
for (i = 0; i < sizeof(buf_dest); i++)
printf("%d ", buf_dest[i]);
printf("\n"); return 0;
}

编译,运行:

由于dest没有以'\0'结尾,因此printf打印的信息是错误的,访问的内容已经超过了dest的空间。

测试用例三:内存重叠

参考博客:strcpy函数的实现 - Norcy - 博客园 (cnblogs.com)

#include <stdio.h>
#include <string.h> int main(void)
{
char str[12] = "hello";
strcpy(str + 1, str); //存在段错误
printf("%s\n", str); return 0;
}
#include <stdio.h>
#include <string.h> int main(void)
{
char str[12] = "hello"; strcpy(str, str+1);
printf("%s\n", str); //打印输出ello return 0;
}

第一种情况:strcpy(str + 1, str),这种情况下dest指向'e',而src第一个字符为'h',当拷贝的时候,'\0'结束符会被覆盖掉,导致一直拷贝,陷入死循环。

第二种情况:strcpy(str, str+1),这种情况下,仅拷贝"ello"。

strncpy()函数

头文件:#include <string.h>

函数原型:char *strncpy(char *dest, const char *src, size_t n);

函数描述:功能和strcpy函数类似,但仅拷贝src的n字节给dest。另外如果n字节中没有结束符'\0',那么拷贝完后,dest中是不会有结束符的,这个需要注意。如果src的长度小于n字节,将会在拷贝src字符串之后继续拷贝结束符给dest,直到满足n字节。

函数原型:

char *strncpy (char *s1, const char *s2, size_t n)
{
reg_char c;
char *s = s1; --s1; if (n >= 4)
{
size_t n4 = n >> 2;
for ( ; ; )
{
c = *s2++;
*++s1 = c;
if (c == '\0')
break;
c = *s2++;
*++s1 = c;
if (c == '\0')
break;
c = *s2++;
*++s1 = c;
if (c == '\0')
break;
c = *s2++;
*++s1 = c;
if (c == '\0')
break;
if (--n4 == 0)
goto last_chars;
}
n = n - (s1 - s) - 1;
if (n == 0)
return s;
goto zero_fill;
} last_chars:
n &= 3;
if (n == 0)
return s; do
{
c = *s2++;
*++s1 = c;
if (--n == 0)
return s;
} while (c != '\0'); zero_fill:
do
*++s1 = '\0';
while (--n > 0); return s;
}

测试用例一:src字符串长度大于n,且前n个字符中存在结束符,则只会拷贝到第一个结束符时就结束拷贝。

#include <stdio.h>
#include <string.h> int main(void)
{
char str_original[] = {'a', '\0', 'b', '\0', 'c', 'd', 'e', '\0'};
char str_dest[8] = {0};
int i = 0; strncpy(str_dest, str_original, 8);
for (i = 0; i < 12; i++)
printf("%d ", str_dest[i]);
printf("\n"); return 0;
}

编译,运行:

$ ./a.out
97 0 0 0 0 0 0 0

测试用例二:src字符串长度大于n,且前n个字符中不存在结束符,则会拷贝n个字符。处理这种情况,一般需要自己去在dest末尾添加一个结束符。

#include <stdio.h>
#include <string.h> int main(void)
{
char str_original[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char str_dest[5] = {0};
int i = 0; strncpy(str_dest, str_original, 5);
for (i = 0; i < 5; i++)
printf("%d ", str_dest[i]);
printf("\n"); return 0;
}

编译,运行:

$ ./a.out
97 98 99 100 101

测试用例三:src字符串长度小于n,将会在拷贝src字符串之后继续拷贝结束符给dest,直到满足n字节。

#include <stdio.h>
#include <string.h> int main(void)
{
char str_original[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char str_dest[12] = {0};
int i = 0; for (i = 0; i < 12; i++)
str_dest[i] = 1; strncpy(str_dest, str_original, 12);
for (i = 0; i < 12; i++)
printf("%d ", str_dest[i]);
printf("\n"); return 0;
}

编译,运行:

$ ./a.out
97 98 99 100 101 102 0 0 0 0 0 0

C标准库学习的更多相关文章

  1. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  2. python标准库学习-SimpleHTTPServer

    这是一个专题 记录学习python标准库的笔记及心得 简单http服务 SimpleHTTPServer 使用 python -m SimpleHTTPServer 默认启动8000端口 源码: &q ...

  3. C++STL标准库学习笔记(一)sort

    前言: 近来在学习STL标准库,做一份笔记并整理好,方便自己梳理知识.以后查找,也方便他人学习,两全其美,快哉快哉! 这里我会以中国大学慕课上北京大学郭炜老师的<程序设计与算法(一)C语言程序设 ...

  4. Go标准库学习之OS常用函数

    1.OS基础操作 //获取主机名 os.Hostname() //获取当前目录 os.Getwd() //获取用户ID os.Getuid() //获取有效用户ID os.Geteuid() //获取 ...

  5. C++STL标准库学习笔记(五)set

    前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,这一篇后面主要都是我的记录了,为了防止大片蓝色字体出现,后面就不改蓝色 ...

  6. C++STL标准库学习笔记(二)二分查找

    二.STL中的二分查找算法 1.binary_search 2.lower_bound 3.upper_bound 记得#include<algorithm>! 前言: 在这个笔记中,我把 ...

  7. Python3 标准库学习

    python3.5.6 官方文档  https://docs.python.org/3.5/library/index.html 1.介绍 2.内置函数 3.内置常量 3.1常数添加的 site模块 ...

  8. Python标准库学习之zipfile模块

    ZipFile模块里有两个非常重要的class, 分别是 ZipFile和ZipInfo. ZipFile是主要的类,用来创建和读取zip文件,而ZipInfo是存储的zip文件的每个文件的信息的. ...

  9. python标准库学习-ftplib

    源码: """An FTP client class and some helper functions. Based on RFC 959: File Transfer ...

随机推荐

  1. Java如何利用for循环在控制台输出正方形对角线图形

    1 /* 2 利用循环在控制台输出如下正方形对角线图形 3 * * * * * * * * * * * 4 * * * * 5 * * * * 6 * * * * 7 * * * * 8 * * * ...

  2. linux安装后配置

    1.1 系统设置(自测用,公司不需要) 1.1.1 Selinux系统安全保护 Security-Enhanced Linux – 美国NSA国家安全局主导开发,一套增强Linux系统安 全的强制访问 ...

  3. 【VBA】MsgBox用法

    MsgBox用法: Sub subMsgBox() Dim iok As Byte iok = MsgBox("是否XXX", vbYesNoCancel + vbQuestion ...

  4. webpack 快速入门 系列 - 自定义 wepack 上

    其他章节请看: webpack 快速入门 系列 自定义 wepack 上 通过"初步认识webpack"和"实战一"这 2 篇文章,我们已经学习了 webpac ...

  5. 【题解】[LuoguP3503]「BZOJ2086」[POI2010] Blocks

    题目描述 给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1.经过一定次数的操作 ...

  6. 【dp】10-8题解 vacation

    vacations 原题codeforeces round 363 (Div2) c 题目描述 暑假到了, Pb 正在计划他的假期. Pb 准备假期去体育馆锻炼或看电影.但体育馆和电影院都有可能当天不 ...

  7. Java源码分析:Guava之不可变集合ImmutableMap的源码分析

    一.案例场景 遇到过这样的场景,在定义一个static修饰的Map时,使用了大量的put()方法赋值,就类似这样-- public static final Map<String,String& ...

  8. Pandas高级教程之:处理text数据

    目录 简介 创建text的DF String 的方法 columns的String操作 分割和替换String String的连接 使用 .str来index extract extractall c ...

  9. 如何回答面试中问到的Hibernate和MyBatis的区别

    这边主要是写给那些准备去面试的(没什么经验的)应聘者看的,为了在面试中更好的回答这个问题,我做一个简单的梳理和总结. 作为一名职场新人,经历过多次的面试,由于在简历中提及了Hibernate和MyBa ...

  10. redis学习第一天

    不同于其他的常用关系型数据库,redis是一个非常轻便,体积小,存放键值对的数据库,常用于构建高性能,可扩展的Web应用程序. 这是我第一次接触redis,之前没有使用过,只听说过.因为刚毕业,找工作 ...