重返C语言(四)

指针

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位

位段详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值