指针进阶(4)+字符串函数(1)

目录

指针和数组笔试题解析

字符函数和字符串函数

函数介绍

strlen

strcpy


指针和数组笔试题解析

二维数组

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 [ 0 ] + 1 )));
printf ( "%d\n" , sizeof ( a + 1 ));
printf ( "%d\n" , sizeof ( * ( a + 1 )));
printf ( "%d\n" , sizeof ( & a [ 0 ] + 1 ));
printf ( "%d\n" , sizeof ( * ( & a [ 0 ] + 1 )));
printf ( "%d\n" , sizeof ( * a ));
printf ( "%d\n" , sizeof ( a [ 3 ]));

printf("%zd\n", sizeof(a));——48-数组名a单独放在了sizeof内存,表示整个数组,sizeof(a)计算的是数组的大小,单位是字节;

printf("%zd\n", sizeof(a[0][0]));——4-a[0][0]是数组的第一行第一个元素,这里计算的就是一个元素的大小,单位是字节;

printf("%zd\n", sizeof(a[0]));——16 - a[0]是第一行这个一维数组的数组名,数组名单独放在了sizeof内部,a[0]就表示整个第一行这个一维数组,sizeof(a[0])计算的整个第一行这个一维数组的大小;

printf("%zd\n", sizeof(a[0] + 1));——4/8 - a[0]并非单独放在sizeof内部,也没有&,所以a[0]表示第一行这个一维数组首元素的地址,也就是第一行第一个元素的地址;

a[0] <---> &a[0][0]
a[0]+1 ---> &a[0][1]


printf("%zd\n", sizeof(*(a[0] + 1)));——4 - a[0] + 1是第一行第二个元素的地址,*(a[0] + 1))就是第一行第二个元素;
    
printf("%zd\n", sizeof(a + 1));——4/8,a 作为二维数组的数组名,并没有单独放在sizeof内部,也没有&,a就是数组首元素的地址,也就是第一行的地址, a 的类型是 int(*)[4],a+1 就是第二行的地址,类型是:int(*)[4];

printf("%zd\n", sizeof(*(a + 1)));——16,a+1是第二行的地址,*(a+1)就是第二行,计算的就是第二行的大小,另外一个角度理解:*(a+1) -- a[1];


sizeof(a[1]) - a[1]这个第二行的数组名,单独放在了sizeof内部,计算的是第二行的大小;

printf("%zd\n", sizeof(&a[0] + 1));——4/8,a[0]是第一行的数组名,&a[0]取出的是数组的地址,取出的是第一行这个一维数组的地址,类型就是int(*)[4],&a[0]+1 就是第二行的地址,类型就是int(*)[4];


printf("%zd\n", sizeof(*(&a[0] + 1)));——16,*(&a[0] + 1)得到的就是第二行,计算的就是第二行的大小;

printf("%zd\n", sizeof(*a));//16,a表示数组首元素的地址,也就是第一行的地址,*a 就是第一行,也就相当于是第一行的数组名,*a--> *(a+0) -- a[0];

printf("%zd\n", sizeof(a[3]));//16-不会越界;
a[3] --    arr[0]
int [4]    int [4]

指针笔试题

int main ()
{
int a [ 5 ] = { 1 , 2 , 3 , 4 , 5 };
int * ptr = ( int * )( & a + 1 );
printf ( "%d,%d" , * ( a + 1 ), * ( ptr - 1 ));——2,5;
return 0 ;
}

这里告知结构体的大小是 20 个字节
struct Test
{
int Num ;
char * pcName ;
short sDate ;
char cha [ 2 ];
short sBa [ 4 ];
} * p ;
假设 p 的值为 0x100000
已知,结构体 Test 类型的变量大小是 20 个字节
int main ()
{
printf ( "%p\n" , p + 0x1 );——结构体指针+1,跳过一个结构体的大小,+20,00100014;
printf ( "%p\n" , ( unsigned long ) p + 0x1 );——无符号整型+1,0010001;
printf ( "%p\n" , ( unsigned int* ) p + 0x1 );——无符号整型指针+4,0010004;
//%p打印地址
return 0 ;
}
int main ()
{
int a [ 4 ] = { 1 , 2 , 3 , 4 };
int * ptr1 = ( int * )( & a + 1 );4,&a地址+1跳过整个数组,然后强制类似转换成指针,因为是数组的地址,+1还是数组的地址;
int * ptr2 = ( int * )(( int ) a + 1 );a转换成整型然后+1,第一个元素整型占四个字节,只是跳过四个元素的第一个字节
printf ( "%x,%x" , ptr1 [ - 1 ], * ptr2 );——4,2000000;
//ptr1[-1]==*(ptr1-1),因为是整型指针,-1就是向前一个整型,拿到的就是4;
return 0 ;
}
*ptr2整型指针向后访问4个字节,然后小端存储就是2000000;
#include <stdio.h>
int main ()
{
int a [ 3 ][ 2 ] = { ( 0 , 1 ), ( 2 , 3 ), ( 4 , 5 ) };
int * p ;
p = a [ 0 ];
//a[0]==&a[0][0];
printf ( "%d" , p [ 0 ]);——1;
//p[0]==*(p+0);
return 0 ;
}
int main ()
{
int a [ 5 ][ 5 ];
int ( * p )[ 4 ];//指针数组
p = a ;
printf ( "%p,%d\n" , & p [ 4 ][ 2 ] - & a [ 4 ][ 2 ], & p [ 4 ][ 2 ] - & a [ 4 ][ 2 ]);——(-4),FFFFFFFC(以16进制打印)
return 0 ;
}
int main ()
{
int aa [ 2 ][ 5 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };
int * ptr1 = ( int * )( & aa + 1 );
int * ptr2 = ( int * )( * ( aa + 1 ));
//* ( aa + 1 )==a[1]==&aa[a][0];
printf ( "%d,%d" , * ( ptr1 - 1 ), * ( ptr2 - 1 ));——10,5;
return 0 ;
}
#include <stdio.h>
int main ()
{
char * a [] = { "work" , "at" , "alibaba" };
char** pa = a ;
pa ++ ;
printf ( "%s\n" , * pa );
return 0 ;
}
int main ()
{
char * c [] = { "ENTER" , "NEW" , "POINT" , "FIRST" };
char** cp [] = { c + 3 , c + 2 , c + 1 , c };
char*** cpp = cp ;
printf ( "%s\n" , **++ cpp );
printf ( "%s\n" , *--*++ cpp + 3 );
printf ( "%s\n" , * cpp [ - 2 ] + 3 );
printf ( "%s\n" , cpp [ - 1 ][ - 1 ] + 1 );
return 0 ;
}

**++cpp——++跳过一个char*的元素,解引用通过地址找到c+2,在解引用找到POINT;

*--*++cpp+3——++运算符较高,先++cp,跳过一个char*的元素,解引用通过地址找到c+1,在--就是c,解引用通过地址找到E的地址,在+3得到的是E的地址,打印就是ER;

*cpp[-2]+3==**(cpp-2)+3——cpp-2就得到c+3,解引用通过地址找到F的地址,在+3得到的是S的地址,打印就是ST,cpp的值没有边;

cpp[-1][-1]+1==*(*(cpp-1)-1)+1——cpp值没变,cpp-1拿到的是c+2,c+2-1就变成c+1了,解引用找到N的地址,打印就是EW;

字符函数和字符串函数

求字符串长度

  • strlen

长度不受限制的字符串函数

  • strcpy
  • strcat
  • strcmp

长度受限制的字符串函数介绍

  • strncpy
  • strncat
  • strncmp

字符串查找

  • strstr
  • strtok

错误信息报告

  • strerror

字符操作

内存操作函数

  • memcpy
  • memmove
  • memset
  • memcmp

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在
常量字符串中或者字符数组 中;
字符串常量适用于那些对它不做修改的字符串函数;

函数介绍

strlen

库函数,是用来求字符串长度的;

本质上统计的是字符串中\0之前的字符的个数

size_t strlen ( const char * str );
  • 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' );
  • 参数指向的字符串必须要以 '\0'结束;
  • 注意函数的返回值为size_t,是无符号的;

代码:

#include <stdio.h>
#include<string.h>
int main()
{
	
	if (strlen("bbb") - strlen("abcdef") > 0)
	{
		printf(">=\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

strlen函数的模拟实现:

三种方式:
方式 1
//计数器方式
int my_strlen(const char * str)
{
 int count = 0;
 while(*str)
 {
 count++;
 str++;
 }
 return count;
}
方式 2
//不能创建临时变量计数器
int my_strlen(const char * str)
{
 if(*str == '\0')
 return 0;
 else
 return 1+my_strlen(str+1);
}
方式 3
//指针-指针的方式
int my_strlen(char *s)
{
       char *p = s;
       while(*p != ‘\0’ )
              p++;
       return p-s;
}

两个无符号数相减得到的还是无符号数;

strcpy——字符串拷贝

char * strcat ( char * destination, const char * source );

  • 源字符串必须以 '\0' 结束;
  • 目标空间必须有足够的大,能容纳下源字符串的内容;
  • 目标空间必须可修改;

代码:

#include <string.h>

int main()
{
	char arr1[20] = {0};
	char arr2[] = "HELLO";

	strcpy(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

srcpy函数的模拟实现:

#include<stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);

	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "abc";
	/*
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	*/

	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

strcpy函数返回的是目标空间的起始地址;

持续更新中.........

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值