指针
char* p="abcdef"——常量字符串,不能修改(只能用,不能改)
int main()
{
int a=10;
int b=20;
int c=30;
int *arr[3]={&a,&b,&c};//数组中存储的是a,b,c的地址
int arr1[]={1,2,3};
int arr2[]={2,3,4};
int arr3[]={3,4,5};
int *arr[]={arr1,arr2,arr3};
int i=0;
for(i=0;i<3;i++)
{
int j=0;
for(j=0;j<3;j++)
{
printf("%d ",arr[i][j]);
//此时arr[i]就相当于arr1/arr2/arr3中的某一个数组名,就能取出相对应数组中的数据,算是另一种二维数组的读取方式和表达方式
}
printf("\n");
}
return 0;
}
数组指针(指向数组的指针)
int arr[10]={1,2,3,4,5,6,7,8,9,0}; int(*p)[10]=&arr; //其中&arr是数组地址;p是数组指针——常用语二维及多维数组
&数组名——拿到的是数组地址
p就是数组指针,指针指向了一个数组,指向的数组里有10个元素,每个元素类型为int
数组指针的使用常用于二维及多维数组
int main() { int arr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}}; print2(arr,3,5); return 0; } //把二维数组想象成一维数组,二维数组中每一行数据就是一维数组的一个元素 void print2(int(*p)[5],int x,int y) { int i=0; for(i=0;i<3;i++) { int j=0; for(j=0;j<5;j++) { printf("%d ",(*(p+i))[j]; } printf("\n"); } }
int*p1[10]; int (*p2)[10]; p2=&p1;//——可以吗?
不可以!!!
int(*p2)[10]中元素类型为int,而p1中元素类型是int*,可以写成in*(*p2)[10]=&p1
函数指针
int (*pf)(int,int)=&Add; int Add(int x,int y); sum=(*pf)(2,3); sum=pf(2,3);
此时pf和Add的效果是相同的,都可以直接当成函数名来用。
函数名是函数的地址,(&函数名)也是函数的地址。
例:
函数指针数组
int(*pf[4])(int,int)={Add,Sub};
指向函数指针数组的指针
int (*pf[5])(int,int); int((*pf)[5])(int,int)=&pf;
回调函数:通过函数指针调用的函数
void*的指针是无具体类型的指针,可以存储任何类型的指针,不能进行直接的+、-操作,也不能解引用指针。
字符串+内存函数
strlen——返回类型为size_t,直接进行运算时无负数;
size_t→unsigned int 无符号整形(不用定义新变量)
strcpy(arr1,arr2)——arr2是源头字符串,源头字符串里必须包含\0.
使用条件:目标空间必须有足够的空间;目标空间必须可修改。
NUL,Null——'\0'
strcat——追加字符串
char arr[20]="hello "; stract(arr,"world"); //最后生成字符串hello world
导入静态库:
#progma comment(lib,"stract");
strcmp(arr1,arr2)——比较两个字符的大小(按位比较)
在arr1<arr2时,输出值小于0;
在arr1=arr2时,输出值等于0;
在arr1>arr2时,输出值大于0;
_cdecl——函数调用约定
以上三个函数是长度不受限制的字符串操作函数——不安全
strncpy(arr1,arr2,5)——复制过去五个字符
strnact(arr1,arr2,5)——追加过去五个字符
strncmp(arr1,arr2,5)——比较前五个字符
strstr——找子串
例:strstr(arr1,arr2)
判断arr2是否是arr1的子串,如果没找到的话返回空指针(NULL),找到的话返回找到的字符串首地址。
如果在字符串“abcdefgabcdefg”中找“cd”,返回的是红色所示c的地址。
KMP算法找子串——高效(比strstr)
strtok——分割字符串
char* strtok(char* dest,char* sep); //sep阐述是个字符串,定义了用做分隔符的字符集合
举例:
#include <string.h> #include <stdio.h> int main () { char str[80] = "This is - www.runoob.com - website"; const char s[2] = "-"; char *token; /* 获取第一个子字符串 */ token = strtok(str, s); /* 继续获取其他的子字符串 */ while( token != NULL ) { printf( "%s\n", token ); token = strtok(NULL, s); } return(0); } //输出结果为: //This is //www.runoob.com //website
strerror——翻译错误代码,返回错误信息
当调用库函数发生错误的时候,就会有错误码,错误码放在errno这个全局变量中;没有错误时,errno中的值为0。
使用时,通常使用sterror(errno),来显示代码中的错误。
perror——直接打印错误信息
内存相关函数
memcpy(arr1,arr2,sizeof(arr1))
void* memcpy(void* dest,const void* src,size_t num)
意义为:把以src地址为起始的num个字节复制到dest地址中,如果dest中不是空的,则覆盖掉。
例:
int main() { char *s="http://www.runoob.com"; char d[20]; memcpy(d, s+11, 6);// 从第 11 个字符(r)开始复制,连续复制 6 个字符(runoob) // 或者 memcpy(d, s+11*sizeof(char), 6*sizeof(char)); d[6]='\0'; printf("%s", d); return 0; } //运行结果为:runoob
memmove(arr1,arr2,16)——和memcpy功能相同,但是比之更安全。
memmove——如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
memcmp(arr1,arr2,n)——比较(内存中的每个字节)
int memcmp(const void *str1, const void *str2, size_t n)) 把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
- 如果返回值 < 0,则表示 str1 小于 str2。
- 如果返回值 > 0,则表示 str1 大于 str2。
- 如果返回值 = 0,则表示 str1 等于 str2。
memset——内存设置
memset(arr,0,10)——把arr数组的前十个字节设置成0
自定义类型
结构体——一些值的集合
struct stu//数据类型 { char name[20]; short age; char sex[5]; } struct stu s={"张三",20,"男"}; //匿名结构体,只能创建一次 struct { char name[20]; short age; char sex[5]; }s1,s2;
结构体内存对齐(计算结构体的大小)
offsetof(结构体名,变量名)——计算偏移量——<stddef.h>
1、结构体第一个成员偏移量永远为0;
2、每个变量的存储地址为对齐数的整数倍(对齐数:变量大小和编译器默认大小的较小值)
3、最终大小为所有对齐数中的最大值的整数倍
修改默认对齐数——#pragma pack(n),n为修改值,一般改为2^n值
位段
1、成员必须为(int,unsign int,sign int,char)
2、成员明后有冒号和数字
变量命名:字母、数字、下划线组成,数字不在第一位
例:int _a:2→2代表_a只占两个bit位