Tips
1.
2.
3. 在进行数值计算的时候,补码能算对,因此计算机里面放的都是补码,运算的对象都是补码
但是与真实数值吻合的是原码,因此打印,求值等都要转化为原码
4. for (exp1 ; exp2 ; exp3),是先执行exp1,然后判断exp2,为真的话再执行循环体,再执行exp3,然后在进行判断。
5.
前言
strlen()
1. 指针指向的字符串必须要有\0
1. 这个函数是用来求字符串长度的,字符串以\0为结束标志,而strlen从给定的起始指针开始,向后一直找\0,并统计\0之前的字符个数
2. 这个函数非常在意\0,因此指针指向的字符串必须得有\0,如果没有的话,那么结果就是不可控的随机值
3. 尤其要注意,strlen()的返回值是size_t(typedef size_t unsigned int),其实这个好理解,因为字符串的长度不可能为负的嘛。但是,就会牵扯到一些使用时的细节问题。
如:
这个应该是比较好解释的,因为strlen的返回值的类型是无符号的整型,当3-6的操作内存中的二进制补码在进行计算的时候,对于结果的类型解读自然也是无符号的整型,那么就不可能为负数,事实上数值就变为很大很大一个数了
4. 模拟实现版本1:(计数法)
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
size_t count = 0;
while (*str++)
{
count++;
}
return count;
}
5. 模拟实现版本2:(递归法)
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
if (*str)
return 1 + my_strlen(str + 1);
else
return 0;
}
6. 模拟实现版本3:(指针相减法)
注:指针减去指针的结果是两个指针之间数组元素个数
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
const char* start = str;
while (*str)
{
str++;
}
return str - start;
}
7. strlen与转义字符结合在一起的一些注意点(对sizeof也适用)
1. 转义字符为一个字符,比如说\n,只计为一个字符,两者是一个整体。
2. 当\不起任何作用时,则单个\不计算在结果内。
3. 编译器会把\000或者\00当成\0,道理对\x000.....也一样。
4. 当strlen()碰到\0时就会停下来不在计数!\0不包括在内!,而sizeof()没有影响
strlen非常注意\0,而sizeof完全不在乎,直接统计在内 ,字符串末尾默认带有一个\0的!
strcpy()
1. 源头指针指向的字符串必须要有\0
2. 并且\0也必须一起拷贝过来
1,这个函数就是拷贝字符串,那拷贝到什么时候会停止呢?源头的数据拷贝到\0的时候就停止。
2. 拷贝的时候源头指针指向的字符串的\0也会被拷贝过来,并且覆盖掉目标指针指向的字符串的\0
3. 如果在源头指针指向的字符串里面提前放个\0,那么拷贝就会提前终止
4. 并且目标空间必须足够大
5. 并且目标指针指向的内存空间必须是可以修改的,如果说是一个字符串常量,那就完了
6. 并且当源头指针指向的字符串长度小于目标指针指向的字符串长度时,
7, 并且strcpy的返回值是目标指针
8. 模拟实现strcpy()
char* my_strcpy(char* dest, const char* src)
{
assert(src && dest);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
strcat()
1. 源头指针与目标指针指向的字符串都要有\0
2. 会将目标指针指向的字符串末尾\0覆盖掉
1. 是用来完成追加字符串的,其函数原型与strcpy一模一样
2. 把源头指针指向的字符串追加到目标指针指向的字符串后面
3. 我得找到目标指针指向的字符串的\0才能追加,因为必须以此作为追加的起点
4. 同时源头指针指向的字符串也必须有\0存在,表明追加到什么时候停下来
5. 当然,目标空间也必须得十分大,同时,返回的也是目标指针
6,如果提前在目标指针指向的字符串里面遇见了\0,就直接开始以此为起点追加
7. 模拟实现strcat()
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
8, 用strcat自己给自己追加的时候会有bug,因为会把我自己的\0给自己覆盖掉,这下好了,\0没了,直接死循环裂开了
strcmp()
1. 两两对应位置字符的ASCII码一一比较时,\0可能会参与比较
1. 这个是比较两个字符串
2. 是一一比较对应位置上字符的ascii码值,不是比较字符串长度
3. 其函数返回形式与qsort函数的比较函数十分类型
4. strcmp()模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
if (*str1 > *str2)
{
return 1;
}
else
{
return -1;
}
}
上面我们讲的如strcpy,strcat,strcmp都是长度不受限制的字符串函数,什么意思呢?一切到\0为止,我压根儿才不关心你几个,无所谓没有长度限制,一直到\0为止,我才不关心能不能放得下或者说拷贝几个,一直下去到\0为止
长度受限制的字符串函数
1. 但是这会让人很不安全,为了稍微安全一点,就有了 长度受限制的字符串函数如:strncpy,strncat,strncmp
2. 它们在原先的基础之上参数也多了一个,当然之前的参数肯定是不会发生变化的
3. 多的参数就是n, 也就是拷贝几个字符?追加几个字符?比较几个字符?
strncpy()
如果我要拷贝的字符数小于源头指针指向的字符串字符数
这时候你会发现\0是不会被拷贝过来的
如果我要拷贝的字符数大于源头指针指向的字符串字符数
这时候你会发现多余拷贝的内容用\0来代替
strncat()
如果我要追加的字符数小于源头指针指向的字符串字符数
你会发现你要求的我追加完后会在结尾放入一个\0
如果我要追加的字符数大于源头指针指向的字符串字符数
你会发现如果source中C字符串的长度小于num,则只追加到结束空字符的内容
strncmp()
这个就很为简单了
字符串查找函数
1. strstr( )
2. strtok( )
strstr()
1, 其实就是在str1中查找str2在str1中第一次出现的位置/地址
2. 如果能在str1中找到字串str2,返回 str2在str1中第一次出现的位置/地址
3,如果找不到,返回空指针NULL
4. 模拟实现strstr()
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == '\0')
return (char*)str1;
char* cp = (char*)str1;
char* s1 = NULL;
char* s2 = NULL;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 == *s2)
{
s1++;
s2++;
if (*s2 == '\0')
return cp;
}
cp++;
}
return NULL;
}
附:
怪异函数strtok()
1. 第一个参数是要么是一个指向字符串的指针,要么是一个空指针NULL
2. 第二个参数是一个指向字符串的指针,该字符串是当作分隔符的字符集合
(标记:在字符串中被分隔符分隔开的若干个字符集合就是标记,比如说“ad.fgf.ddffss”,那么如果.是分隔符,则,ad,fgf,ddffss这三个东西就被称为标记
怪异函数工作步骤
1. 如果第一个参数不是一个NULL,而是一个指向字符串的指针的话,
2. 那么就先找到第一个标记。
3. 将找到的标记的结尾把分隔符去掉变成\0
4. 返回指向该标记(小字符串)的指针
5. 有记忆功能(实质就是函数体里面有static修饰的变量),strtok函数将保存第一个标记在字符串
中的位置。
6. 如果下一次调用strtok()此时第一个参数是NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。如果字符串中不存在更多的标记,则返回 NULL 指针。
实例演示
但事实上,上面这种写法就显得有点痤,可以这样子写:
注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。(strcpy派上用场了)