二维数组 结构体01 day15,16
十五:二维数组
一:int *p [4]
(p+i)
//i
可以取0 1 2 此时的p+i
相当于获得了 int[4] a[3]
这个一维数组的一整个元素所在空间的地址
*(p+i)
//*(p+i)
—此时就相当于 是一个int[4]
类型的数据
对具体元素的访问 //*(*(p+i)+ j)
//等价于p[i][j]
在指向行的指针前面加一个*,就转换为指向列的指针。例如,a和a+l是指向行的指针,在它们 前面加一个*就是a和 (a+l), 它们就成为指向列的指针,分别指向 a数组 0行 0 列 的元素和 1 行0列的元素。反之,在指向列的指针前面加&,就成为指向行的指针。
例如,a和a+l是指向行的指针,在它们 前面加一个*就是a和 (a+l), 它们就成为指向列的指针,分别指向 a数组 0行 0 列 的元素和 1 行0列的元素。反之,在指向列的指针前面加&,就成为指向行的指针。
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};int (*p)[4] = a;int j = 0;int i = 0;for(i=0;i<3;i++){for(j=0;j<4;j++){printf("%d ",*(*(p+i)+j));}}putchar('\n');
void printfArray(int (*a)[4],int row)//函数形式
{int j = 0;int i = 0;for(i=0;i<row;i++){for(j=0;j<4;j++){printf("%d ",*(*(a+i)+j));//先访问一维,在一维的基础 j 访问二维}}putchar('\n');}
int max(int (*a)[4],int row)
{int j = 0;int i = 0;int max = *(*(a+0)+0);for(i=0;i<row;i++){for(j=0;j<4;j++){if(*(*(a+i)+j) > max){max =*(*(a+i)+j); }}}return max;}
二:字符型二维数组
#include<stdio.h>void PrintChar(char (*s)[10],int row)
{for(int i=0;i<3;i++){printf("%s\n",*(s+i));}}int main(int argc, const char *argv[])
{char s[3][10] = {"hello","wolrd","china"};char (*p)[10] = s;PrintChar(s,3);return 0;
}
void ReversePrintfArray(char (*begin)[10],char (*end)[10])
{while(begin<end){char t[10];strcpy(t,*begin);strcpy(*begin,*end);strcpy(*end,t);++begin;--end;}
}void PrintChar(char (*s)[10],int row)
{for(int i=0;i<3;i++){printf("%s\n",*(s+i));}}
int main(int argc, const char *argv[])
{char s[3][10] = {"hello","world","china"};PrintChar(s,3);ReversePrintfArray(s,s+2);PrintChar(s,3);return 0;
}
void chosen(char (*s)[10],int row)//选择
{for(int i=0;i<row-1;++i){for(int j=i+1;j<row;++j){if(strcmp(*(s+i),*(s+j))>0){char t[10];strcpy(t,*(s+i));strcpy(*(s+i),*(s+j));strcpy(*(s+j),t);}}}
}
三:二重指针
#include<stdio.h>
#include<string.h>char * findMax(char* *p,int len)
{char* max = *p;for(int i=1;i<len;i++){if(strcmp(max , *(p+i))< 0){max = *(p+i);}}return max;
}void printStr(char* *p,int len)
{int i = 0;for(i=0;i<len;++i){printf("%s\n",*(p+i));}
}int main(int argc, const char *argv[])
{char* p[3] = {"hello","world","china"};printStr(p,3);printf("maxChar = %s\n",findMax(p,3));return 0;
}
void chosen(char* *s,int row)//选择
{for(int i=0;i<row-1;++i){for(int j=i+1;j<row;++j){if(strcmp(*(s+i),*(s+j))>0){char * t = *(s+i);*(s+i) = *(s+j);*(s+j) = t;}}}
}
void reverseChar(char* *begin,char* *end)
{while(begin<end){char *t = *begin;*begin = *end;*end = t;++begin;--end;}
}void printStr(char* *p,int len)
{int i = 0;for(i=0;i<len;++i){printf("%s\n",*(p+i));}
}int main(int argc, const char *argv[])
{char* p[3] = {"hello","world","china"};printStr(p,3);chosen(p,3);printStr(p,3);return 0;
}
char * binaryfindWord(char (*s)[10],int row,const char *str)
{char (*begin)[10] = s;char (*end)[10] = s + row - 1;char (*mid)[10] = NULL;char *ret = NULL;while(begin <=end){mid = begin + (end-begin)/2;if(strcmp(*mid,str)>0){end = mid - 1; }else if(strcmp(*mid,str)<0){begin = mid + 1;}else{ret = *mid;break;}}return ret;
}
char * binaryfindWord(char* *s,int len,char *str)
{char* *begin = s;char* *end = s + len - 1;char* *mid = NULL;char *ret = NULL;while(begin <=end){mid = begin + (end-begin)/2;if(strcmp(*mid,str)>0){end = mid - 1; }else if(strcmp(*mid,str)<0){begin = mid + 1;}else{ret = *mid;break;}}return ret;
}
四:指针指向函数
int add (int a,int b)
//掉函数名,剩下就是函数类型
int (int a,int b)
//代表一类函数 //返回值类型为int
同时带有两个int
型的形参 这么一类函数
基类型 * 变量名
int (int a,int b)
*
p //理解角度)就是一个指向 int (int a,int b)
这种函数的一个指针变量
int (*p) (int ,int )
*
//正确C语言写法
1.函数指针变量可以用来调用函数 //函数入口地址(实参)
2.**
p, *
不起作用
int add(int a,int b)
{return a + b;
}int main(int argc, const char *argv[])
{int (*p)(int ,int ) = add;printf("add = %p\n",add);int ret = p(1,2);printf("ret = %d\n",ret);return 0;
}
int func1(int n)
{return n;
}
int func2(int n)
{return n*n;
}int func3(int n)
{return n*n*n;
}void choiceSortP(int *a,int len,int (*pFunc)(int ))
{int i=0;int j=0;for(i=0;i<len-1;++i){for(j=i+1;j<len;++j){if(pFunc(a[i]) > pFunc(a[j])){int t = a[i];a[i] = a[j];a[j] = t;}}}
}int a[10] = {3,2,1,5,8,9,6,7,4,10};printArray(a,10);choiceSortP(a,10,func3);printArray(a,10);
int func1(int a,int b)
{return a+b;
}
int func2(int a,int b)
{return a-b;
}
int func3(int a,int b)
{return a*b;
}
int func4(int a,int b)
{return a/b;
}void processDate(int a,int b,int (*pfunc)(int ,int))
{printf("result = %d\n",pfunc(a,b));//这里就当正常函数用就行,
}int main(int argc, const char *argv[])
{int a = 1;int b = 2;processDate(a,b,func1);processDate(a,b,func2);processDate(a,b,func3);processDate(a,b,func4);int (*p[4])(int,int) = {func1,func2,func3,func4};//main的另一种写法for(int i=0;i<4;i++){processDate(a,b,p[i]);}return 0;
}
回调函数
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
int compare(const void *a,const void *b)
{const int *p = a;const int *q = b;return *p - *q;
}int main(int argc, const char *argv[])
{int a[10] = {3,1,5,7,9,4,8,0,10,6};int len = sizeof(a)/sizeof(a[0]);qsort(a,len,sizeof(int),compare);for(int i=0;i<len;i++){printf("%d ",a[i]);}putchar('\n');return 0;
}
int compare(const void *s1,const void *s2)
{const char *p = s1;const char *q = s2;return strcmp(p,q);
}int main(int argc, const char *argv[])
{char s[5][10] = {"hello","world","china","english","america"};qsort(s,5,sizeof(char[10]),compare);for(int i=0;i<5;i++){puts(s[i]);}return 0;
}
五:malloc和free
void *malloc(size_t size);
功能:申请内存 //堆区
参数:size //表示申请的空间大小单位字节 返回值:void*
成功:返回申请到的内存空间的首地址
失败:NULL
堆区空间的特点:1.空间大2.手动申请,手动释放
void free(void *ptr);
//释放
功能:将堆区空间释放 //将之前在用的空间交还给操作系统,告诉操作系统,说这块空间不用了,可以回收
参数:ptr
//要求:代表堆区上的一块空间,free
用之前前一定有malloc已经申请使用过的 堆区空间
void*
//空类型指针, void *p
//指针变量-可以接受任意类型
指针函数,意味着返回值是个地址,这个地址,不能是局部变量的地址
int *p = malloc(sizeof(int));printf("1 p = %p\n",p);*p = 0x12345678;printf("%#x\n",*p);free(p);//此时p悬空指针p =NULL;printf("2 p = %p\n",p);printf("*p = %d\n",*p);
----------------------------------
1 p = 0x560c533a5260
0x12345678
2 p = (nil)
Segmentation fault (core dumped)
int *p = malloc(10*sizeof(int));//将数组放进堆区for(int i=0;i<10;i++){*(p+i) = i + 1;}int sum = 0;for (int i = 0; i < 10; i++){sum +=*(p+i);}printf("sum = %d\n", sum);free(p);p =NULL;
void getmemory(char *p,int num)
{p =(char *)malloc(num);//仅修改局部变量 p
}int main()
{char *str = NULL;getmemory(str,100);//最终开辟的是全是NULL的空间,函数参数是 局部变量的拷贝,修改 p 不会影响 strstrcpy(str,"hello");//NULL是零号地址空间,无法访问,段错误puts(str);return 0;
}
void *getmemory(char **p,int num)
{*p =(char *)malloc(num);
}int main()
{char *str = NULL;getmemory(&str,100);//要想修改指针的指向,必须传递指针的地址(二级指针)://类似 swap(int *a, int *b) 需要传递 &a 和 &b 才能交换值。strcpy(str,"hello");puts(str);return 0;
}
六:多级指针
int a = 10;int *p = &a;int **q = &p;int ***r = &q;printf("a = %d\n",a);printf("*p = %d\n",*p);printf("**q = %d\n",**q);printf("***r = %d\n",***r);
七:main函数
@argc
表示 — 命令行参数的个数
@argv
表示 — 存放着命令行字符串的指针数组
int main(int argc, const char *argv[])
{printf("argc = %d\n",argc);int i=0;for(i=0;i<argc;++i){printf("argv[%d] = =%s\n",i,argv[i]);}return 0;
}
十六:结构体
一:语法
struct 结构体名
{//各个成员变量//变量形式//结构体类型的定义
};
eg:
struct studnet
{char name[20];int socre;int sno;int sex;
}//此时我们自定义了一种数据类型---叫学生类型,类型名struct student
#include<stdio.h>struct studnet
{char name[20];int socre;int sno;int sex;
};int main()
{struct studnet s = {"tom",90,110,1};printf("name = %s\n",s.name);return 0;
}
scanf
struct studnet s;scanf("%s",s.name);scanf("%d",&s.socre);scanf("%d",&s.sno);scanf("%d",&s.sex);
void printStuinfo(struct studnet *s)
{printf("name = %s\n",s->name);printf("socre = %d\n",s->socre);printf("sno = %d\n",s->sno);printf("sex = %d\n",s->sex);}struct studnet s;printStuinfo(&s);
相同类型的结构体变量之间可以相互赋值
struct studnet t = s[2];
结构体类型的形参,一般设计为指针类型,原因://指针类型传参时大小固定,
//如果是结构体类型变量,变量的大小取决于结构体类型的大小
二:通过指针
->
//指向结构体成员运算符
结构体类型的指针->
结构体的成员变量
struct studnet s;scanf("%s",s.name);scanf("%d",&s.socre);scanf("%d",&s.sno);scanf("%d",&s.sex);struct studnet *p = &s;printf("name = %s\n",p->name);printf("socre = %d\n",p->socre);printf("sno = %d\n",p->sno);printf("sex = %d\n",p->sex);