前言

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. OpenCV读写图像文件解析

    OpenCV读写图像文件解析 imdecode 从内存中的缓冲区读取图像. C++:Mat imdecode(InputArray buf, int flags) C++:Mat imdecode(I ...

  2. UF_TRNS 变换相关

    Open C uf5940uf5941uf5942  矩阵乘积变换uf5943  平移变换uf5944  缩放变换uf5945  旋转变换uf5946  镜像变换uf5947  实现变换,根据变换矩阵 ...

  3. 摆脱鼠标之Dos学习

    2015/12/24 for循环 1,创建文件 http://blog.csdn.net/wangxingbao4227/article/details/17009447 关于for循环的总结,很详细 ...

  4. 【Java】Debug断点调试常用技巧

    Debug操作技巧 Show Execution Point 将光标回到当前断点停顿的地方 Step Over 执行当前行代码,并将运行进度跳转到下一行. Step Into 进入到当前代码行的方法内 ...

  5. NOIP模拟测试29「爬山·学数数·七十和十七」

    爬山题解不想写了 学数数 离散化然后找到以每一个值为最大值的连续子段有多少个,然后开个桶维护 那么怎么找以每一个值为最大值的连续子段个数 方法1(我的极笨的方法) 考试时我的丑陋思路, 定义极左值为左 ...

  6. 带你掌握4种Python 排序算法

    摘要:在编程里,排序是一个重要算法,它可以帮助我们更快.更容易地定位数据.在这篇文章中,我们将使用排序算法分类器对我们的数组进行排序,了解它们是如何工作的. 本文分享自华为云社区<Python ...

  7. Hive和Spark分区策略

    1.概述 离线数据处理生态系统包含许多关键任务,最大限度的提高数据管道基础设施的稳定性和效率是至关重要的.这边博客将分享Hive和Spark分区的各种策略,以最大限度的提高数据工程生态系统的稳定性和效 ...

  8. ES6学习笔记之字符串新增方法

    1.字符串的子串识别 传统上,Javascript 只有indexof 方法,用来确定一个字符串是否包含在另一个字符串中.如: //indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的 ...

  9. 38、mysql数据库(pymysql及事务)

    38.1.python之pymysql模块: 1.说明: pymsql是Python中操作MySQL的模块,其使用方法和py2的MySQLdb几乎相同. 2.模块安装: pip install pym ...

  10. CentOS-配置YUM源加速(阿里云、Nexus3)

    备份本地源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 配置CentOS6(aliyun ...