前言

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. 视频系列:RTX实时射线追踪(上)

    视频系列:RTX实时射线追踪(上) Video Series: Practical Real-Time Ray Tracing With RTX RTX在游戏和应用程序中引入了一个令人兴奋的和根本性的 ...

  2. 利用NVIDIA-NGC中的MATLAB容器加速语义分割

    利用NVIDIA-NGC中的MATLAB容器加速语义分割 Speeding Up Semantic Segmentation Using MATLAB Container from NVIDIA NG ...

  3. python_selenium_键盘事件

    引言 ----在实际的web测试工作中,需要配合键盘按键来操作,webdriver的  keys()类提供键盘上所有按键的操作,还可以模拟组合键Ctrl+a,Ctrl+v等. 举例: #cording ...

  4. 深入理解java虚拟机笔记补充-JVM常见参数设置

    JVM 常见参数设置 内存设置 参数 -Xms:初始堆大小,JVM 启动的时候,给定堆空间大小. -Xmx:最大堆大小,如果初始堆空间不足的时候,最大可以扩展到多少. -Xmn:设置年轻代大小.整个堆 ...

  5. 已经安装好了tensorboardX,任然报错 No module named ‘tensorboardX‘ ??

    问题: 1.在jupyter notebook网页版中已经使用命令pip install tensorboardX来安装tensorboardX包,但是运行程序时仍旧出现错误:No module na ...

  6. P1045 [NOIP2003 普及组] 麦森数

    题目描述 形如2^P−1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P−1不一定也是素数. 到1998年底,人们已找到了37个麦森数.最大的一个是P=3021377, ...

  7. ES6中的字符串

    字符串在编程语言中,一直是使用率很高的数据,虽说函数在js语言中是一等公民,但是字符串,怎么也能算得上是千年老二,下面我就一起和大家探讨一下在es6中的一些新用法和特性,特别是在字符串拼接的时候,会解 ...

  8. CMake 两种变量原理

    目录 [TOC] 1.两种变量的定义参考 2.两种变量的作用域原理及使用 1.Normal Variables (1).包含 add_subdirectory().function().(本质是值拷贝 ...

  9. 透彻理解液晶显示模组LCD1602指令集与驱动编程(1)

    LCD1602可以说是大多数单片机工程师了解液晶显示的入门级模组,其显示原理与其它很多显示模组也是相似的,今天我们就来详细讨论一下它的指令集.所谓模组的指令集,本质上是该模组使用的控制芯片的指令集,本 ...

  10. Java中对象调用方法的顺序

    Java虚拟机会预先为加载到内存中的每个类维护一个方法表(Method Table),其中列出了所有类中所有方法的签名. 现在有2个类A和B,其中,B是A的子类,和一个B类型的对象x,当调用x.f(a ...