目录
指针和数组笔试题解析
二维数组
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 ;}
#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
函数介绍
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函数的模拟实现:
//计数器方式
int my_strlen(const char * str)
{
int count = 0;
while(*str)
{
count++;
str++;
}
return count;
}
//不能创建临时变量计数器
int my_strlen(const char * str)
{
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
//指针-指针的方式
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函数返回的是目标空间的起始地址;
持续更新中.........