【常问基础】02.基本函数
【嵌入式八股】一、语言篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM
【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym
【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM
【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0
02.基本函数
( C语言标准库函数大全(ctype、time 、stdio、stdlib、math、string)_冬瓜~的博客-CSDN博客_c语言库函数
C语言C++中assert的用法 - 知乎 (zhihu.com)
40.strcpy和memcpy的区别是什么?
函数原型
char *strcpy(char *dest, const char *src);
void *memcpy(void *dest, const void *src, size_t n);
1、复制的内容不同(用途不同)。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、strcpy函数的返回值是目标字符串的指针,而memcpy函数的返回值是目标内存块的指针。
41.strcpy、sprintf与memcpy这三个函数的不同之处
-
操作对象不同
① strcpy的两个操作对象均为字符串,
② sprintf的操作源对象可以是多种数据类型,目的操作对象是字符串
③ memcpy的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。
-
执行效率不同
memcpy最高,strcpy次之,sprintf的效率最低。
-
实现功能不同
① strcpy主要实现字符串变量间的拷贝
② sprintf主要实现其他数据类型格式到字符串的转化
③ memcpy主要是内存块间的拷贝。
42.strcpy函数和strncpy函数的区别?哪个函数更安全?
函数原型
char* strcpy(char* strDest, const char* strSrc)
char *strncpy(char *dest, const char *src, size_t n)
strcpy函数: 如果参数 dest 所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。
strncpy函数更安全:用来复制源字符串的前n个字符,src 和 dest 所指的内存区域不能重叠,且 dest 必须有足够的空间放置n个字符。
- 如果目标长>指定长>源长,则将源长全部拷贝到目标长,自动加上’\0’
- 如果指定长<源长,则将源长中按指定长度拷贝到目标字符串,不包括’\0’
- 如果指定长>目标长,运行时错误 ;
43.C语言中memcpy和memmove是一样的吗?
相同:memcpy()与memmove()一样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上。
不同:当src和dest所指的内存区域重叠时,memcpy可能无法正确处理,而memmove()仍然可以正确处理,不过执行效率上略慢些。
内存块的重叠指的是两个或多个内存块在地址空间中有一部分是重合的情况。具体来说,如果两个内存块
A
和B
的地址空间中有重合部分,则我们称它们之间存在内存块重叠。
memcpy()无论什么情况下,都是从前往后拷贝内存。当源地址在前,目的地址在后,且两个区域有重叠时,会造成拷贝错误,达不到理想中的效果。
void *memcpy(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_dest = (char *)dest;
char *tmp_source = (char *)source;
while(count --)//不对是否存在重叠区域进行判断
*tmp_dest ++ = *tmp_source ++;
return dest;
}
举个例子,假设有一个内存块A
,它的地址空间是[0x100, 0x104]
,存储了4个整数0x11
、0x22
、0x33
和0x44
。现在要将内存块A
中的数据复制到内存块B
中,假设内存块B
的地址空间是[0x102, 0x106]
。这时,内存块A
的第二个和第三个字节0x22
和0x33
正好落在内存块B
的前两个字节上。如果使用memcpy
函数进行复制,那么在执行复制操作时就会把A
中的0x22
和0x33
复制到B
中,导致B
中的前两个字节的值变为0x2233
,这显然不是我们期望的结果。在这种情况下,应该使用memmove
函数来避免内存块重叠导致的问题。
(2)memmove()则分两种情况:目的地址在前,源地址在后的情况下,从前往后拷贝内容。否则从后往前拷贝内容。无论什么情况都能达到理想中的效果。
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果没有重叠区域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重叠
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}
44.手写函数:strlen(), strcpy(), strstr(), strcat(), strcmp()
- strlen函数
功能:计算给定字符串的(unsigned int型)长度,不包括'\0'在内
#include <bits/stdc++.h>
using namespace std;
int strlen(const char *str) {
assert(str != NULL); //assert(str);就行
int len = 0;
while( (*str++) != '\0')
len++;
return len;
}
int main(void)
{
const char a[] = "963852";
int ret = mystrlen(a);
cout << ret << endl;
return 0;
}
- strcpy()函数
C语言库函数模拟实现之strcpy_哔哩哔哩_bilibili
功能:字符串复制函数,strcpy把含有'\0'结束符的字符串复制到另一个地址空间,返回值的类型为char*。
#include <bits/stdc++.h>
using namespace std;
char* mystrcpy(char *dest, const char *src) {
assert(dest && src);
char *ret = dest;
while((*dest++ = *src++) != '\0');
return ret;
}
int main(void)
{
const char a[] = "963852";
char b[10] = "";
char* ret = mystrcpy(b,a);
cout << ret << endl;
return 0;
}
注意:在该函数中,ret
指针所指向的内存空间是在函数的栈帧中分配的。栈帧是函数在运行时所占用的内存空间,其中包括函数参数、局部变量、返回地址等。当函数执行完毕后,该栈帧会被弹出,函数的所有局部变量和参数也会被销毁。因此,ret
指针所指向的内存空间在函数执行完毕后就已经被销毁,此时如果再使用该指针访问该内存空间,就会导致未定义行为,可能会出现意想不到的错误。
然而,这里的代码中返回的是 dest
指针,而不是 ret
指针。ret
指针仅仅用于保存 dest
的初始值,而在函数执行过程中并没有改变。因此,返回 ret
指针并不会导致问题。
需要注意的是,如果函数返回的是指向函数内部局部变量的指针,那么在函数执行完毕后,该指针指向的内存空间就已经被销毁,因此使用该指针可能会导致未定义行为。
- strcat()函数
功能:把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。要保证*dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。
#include <bits/stdc++.h>
using namespace std;
char* mystrcat(char* dest, const char* src) {
assert(dest && src);
char* ret = dest;
while((*dest++) != '\0'); //当strDest='\0'时结束,即为字符串的结尾,将strSrc添加到此处
dest--;
while((*dest++ = *src++) != '\0'); //将src拷贝到dest
return ret;
}
int main(void)
{
const char a[] = "963852";
char b[20] = "147";
char* ret = mystrcat(b, a);
cout << ret << endl;
return 0;
}
- strcmp()函数
功能:对两个字符串进行比较,若s1、s2字符串相等,则返回零;若s1大于s2,则返回正数;否则,则返回负数。
#include <bits/stdc++.h>
using namespace std;
int strcmp(const char* str1, const char* str2) {
assert(str1 && str2);//assert((str1 != NULL) && (str2 != NULL));
int ret = 0;
//ret=0,相等,相等时要确定两个字符不为'\0'; ret!=0时,循环结束,判断ret值
while( !(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1 ) {
str1++;
str2++;
}
if(ret > 0) return 1;
else if(ret < 0) return -1;
return 0;
}
int main(void)
{
const char a[] = "963852";
char b[20] = "147";
int ret = mystrcmp(b, a);
cout << ret << endl;
return 0;
}
- strstr()函数
功能:strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。
#include <bits/stdc++.h>
using namespace std;
int strstr(const char *str, const char *substr) {
assert(str && substr);
int lenstr = strlen(str);
int lensub = strlen(substr);
if(lenstr < lensub)
return -1;
int i,j;
for(int i = 0; i <= lenstr-lensub; ++i) {
for(j = 0; j < lensub; ++j) {
if(str[i+j] != substr[i])
break;
}
if(j == lensub)
return i;
}
return -1;
}
int main(void)
{
const
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇【本专栏】 2.计算机基础 3.硬件篇 4.嵌入式Linux (建议PC端查看)