文章目录
模拟实现strlen
- 递归
int my_strlen(char *str)
{
if(*str == '\0')
{
return 0;
}
else
{
return 1+my_strlen(str+1);
}
}
int my_strlen(char *str)
{
char *p = str;
while(*p!='\0')
{
p++;
}
return p-s;
}
模拟实现strcpy
char *my_strlcpy(char *str1,char*str2)
{
char *ret = str1;
// str1 的起点保存
// 断言
assert(str1!='\0');
assert(str2!='\0');
while(*str1++ = *str2++);
return ret;
}
模拟实现strcat
注意*++str与*str++
char *my_strcat(char*str1,char*str2)
{
char *ret = str1;
// str1 的起点保存
// 断言
assert(str1!='\0');
assert(str2!='\0');
while(*++str1);
while(*str1++ = *str2++);
puts(ret);
return ret;
}
模拟实现strstr
C 库函数 char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。
char *my_strstr(const char*str1,const char*str2)
{
assert(str1);
assert(str2);
char*cp = (char*)str1;
char*substr = (char*)str2;
char *s1 = NULL;
if(*str2 == '\0')
return NULL;
while(*cp)
{
// 重置substr
s1 = cp;
substr = (char*)str2;
while(*s1 && *substr && (*s1==*substr))
{
s1++;
substr++;
}
// 把str2遍历完了
if(*substr=='\0')
{
return cp;
}
// 否则下一个
cp++;
}
}
模拟实现strcmp
比较字符串
int my_strcmp ( char * src, char * dst)
{
int ret = 0 ;
while( ! (ret = *src - *dst) && *dst)
{
++src;
++dst;
}
printf("%d\n",ret);
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
模拟实现memcpy
C 库函数 void *memcpy(void *str1, const void *str2, size_t n)
**从存储区 str2 复制 n 个字节到存储区 str1。
函数memcpy从str2的位置开始向后复制n个字节的数据到str1的内存位置。
void *my_memcpy(void *str1,const void*str2,int n)
{
void *ptr1 = str1;
while(n--)
{
*(char*)str1 = *(char*)str2;
str1 = (char*)str1+1;
str2 = (char*)str2+1;
}
return (ptr1);
}
拷贝长度::strlen+1 不要漏了’\0’
// 将字符串复制到数组 dest 中//
const char src[50] = "http://www.runoob.com";
char dest[50];
// 拷贝长度::strlen+1 不要漏了'\0'
my_memcpy(dest,src,strlen(src)+1) ;
printf("dest = %s\n", dest);
模拟实现memmove
函数原型:void *memcpy (void *p,void *m, size_t num);
memcpy与strcpy相比,memcpy函数用来做内存拷贝,可以用它拷贝任何数据类型的对象,并且可以指定拷贝的数据长度。stycpy函数也是用来做内存拷贝,并且只能拷贝字符串类型的数据。memcpy并不是遇到"\0"就结束,而是一定会拷贝完num个字节。而strcpy 遇到"\0"就结束。
·如果源空间和目标空间出现重叠,就得使用memmove函数处理。
#include<stdio.h>
#include <assert.h>
#include<string.h>
char *my_memmove(void *str1,const void*str2,int n)
{
char *ptr1 = (char*)str1;
if(str1<str2 || (char*)str1 >= (char*)str2 + n)
{
while(n--)
{
*(char*)str1 = *(char*)str2;
str1 = (char*)str1+1;
str2 = (char*)str2+1;
}
return (ptr1);
}
else
{
str1 = (char*)str1 + n-1;
str2 = (char*)str2 + n-1;
while(n--)
{
*(char*)str1 = *(char*)str2;
str1 = (char*)str1-1;
str2 = (char*)str2-1;
}
}
return ptr1;
}
char str[20] = "qyuwhsjagf";
printf("str = %s\n", str);
my_memmove(str+3, str , 4);
printf("str = %s\n", str);
一维数组
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
16
8
4
8
4
8
8
8
8
一级指针
二维数组
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
48
4
16
8
8
8
16
16
数组名 a 在表达式中也会被转换为和 p 等价的指针!
#include <stdio.h>
int main(){
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
int (*p)[4] = a;
printf("%d\n", sizeof(*(p+1)));
return 0;
}
*(p+1)+1
表示第 1 行第 1 个元素的地址。如何理解呢?
*(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址
因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和 sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。
a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)
((p+1)+1)`表示第 1 行第 1 个元素的值。很明显,增加一个 * 表示取地址上的数据。*
使用指针遍历二维数组
#include <stdio.h>
int main(){
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int(*p)[4];
int i,j;
p=a;
for(i=0; i<3; i++){
for(j=0; j<4; j++) printf("%2d ",*(*(p+i)+j));
printf("\n");
}
return 0;
}
二级指针
指针数组
数组指针
- 当对数组名使用sizeof时,返回的是整个数组占用的内存字节数。当把数组名赋值给一个指针后,再对指针使用sizeof运算符,返回的是指针的大小。
int main(void)
{
int arr[3] = {1,2,3};
int*p = arr;
printf("sizeof(arr)=%d\n",sizeof(arr)); //sizeof(arr)=12
printf("sizeof(p)=%d\n",sizeof(p)); //sizeof(p)=4
return 0;
}
- 数值指针的引用
p[n] == *(p+n)
p[n][m] == *( *(p+n)+ m )
#include <stdio.h>
int main() {
int arr[4][4] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int (*p1)[4]; //数组指针
int *p2[4]; //指针数组
p1 = arr;
printf("使用数组指针的方式访问二维数组arr\n");
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
printf("arr[%d][%d]=%d\t",i,j,*(*(p1+i)+j));
}
printf("\n");
}
printf("\n使用指针数组的方式访问二维数组arr\n");
for (int k = 0; k < 4; ++k) {
p2[k] = arr[k];
初始化指针数组
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
printf("arr[%d][%d]=%d\t",i,j,*(p2[i]+j));
}
printf("\n");
}
return 0;
}
指针和数组的定义、声明
数组参数、指针参数
C 语言中,实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象。
这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。
void change(int a)
{
a++; //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁。age还是原来的age,纹丝不动。
}
int main(void)
{
int age = 19;
change(age);
printf("age = %d\n",age); // age = 19
return 0;
}
函数指针
因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时,会直接去内存中找到age这个数据,然后把它增1。
void change(int* pa)
{
(*pa)++; //因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时,
//会直接去内存中找到age这个数据,然后把它增1。
}
int main(void)
{
int age = 19;
change(&age);
printf("age = %d\n",age); // age = 20
return 0;
}