一 数组
1.1 数组的概念
1.2 一维数组
1.2.1 一维数组的定义
<存储类型> <数据类型> <数组名> [数组下标]存储类型:auto,register,static,extern数据类型:基本数据类型:int,char,float....等数组名:是一个标识符,满足标识符的命名规则数组下标:确定数组张元素的个数例如:int a[10];含义:定义一个名为a的数组,一共10个元素,每个元素都是int类型。
1.2.2 一维数组的性质
#include <stdio.h>int main(int argc, const char *argv[]){int a[4];a[0] = 222;a[1] = 333;a[2] = 444;a[3] = 555;printf("%d %d %d\n",a[0],a[1],a[2]);//数组在定义和使用的时候,数组下表尽量不要使用变量//防止后期变量改变会影响对数组的操作,一般数组下标都是常量或者常量表单大师,宏定义本身也是一个常量表达式,所以可以当做数组下标使用#if 0int num = 10;int b[num];b[2] = 5;int n =3;b[n] = 888;printf("%d %d\n",b[2],b[n]);#endifprintf("sizeof(a) = %ld %ld\n",sizeof(a),sizeof(int)*4);printf("%p\n",&a[0]);printf("%p\n",&a[0]+1);printf("%p\n",a);printf("%p\n",a+1);printf("%p\n",&a);printf("%p\n",&a+1);a++; //数组名是常指针,不能修改return 0;}
1.3 一维数组的初始化和遍历
#include <stdio.h>int main(int argc, const char *argv[]){//如果在函数内部定义一个数组没有初始化,那么每一个元素都是随机值//int a[5];//a = {1,2,3,4,5}; //错误写法//全部初始化//int a[5] = {1,2,3,4,5};//int a[5] = {0}; //全部初始化为0//int a[5] = {}; //有的编译器不支持此种写法//int a[5] = {1,2,3}; //局部初始化,没有赋值的元素自动初始化为0int a[] = {1,2,3,4,5,6,7}; //不指定数组下标,系统会根据初始化的数据的个数设置数组下标printf("sizeof(a) = %ld\n",sizeof(a));/*一维数组的遍历*/int i;for(i = 0 ; i < sizeof(a)/sizeof(a[0]);i++){printf("%d ",a[i]);//printf("a[%d] = %d\n",i,a[i]);}putchar(10);return 0;}
1.4 冒泡排序法
#include <stdio.h>int main(int argc, const char *argv[]){int a[10] = {0};printf("请输入10个数字:\n");int i,j;int length = sizeof(a)/sizeof(a[0]);for(i = 0 ; i < length;i++){scanf("%d",&a[i]);}for(i = 0 ; i < length - 1;i++){for(j = 0 ; j < length - 1 - i;j++){if(a[j] < a[j+1]){#if 0int t = a[j];a[j] = a[j+1];a[j+1] = t;#endif a[j] = a[j] + a[j + 1]; a[j + 1] = a[j] - a[j + 1]; a[j] = a[j] - a[j + 1];}}}for(i = 0 ; i < length;i++){printf("%d ",a[i]);}putchar(10);return 0;}
二 二维数组
2.1 二维数组的定义和性质
存储类型 数据类型 数组名 [行数][列数];例如:int arr[3][4];
#include <stdio.h>int main(int argc, const char *argv[]){int a[2][3] = {{1,2,3},{4,5,6}};//int a[2][3] = {{1},{4,5}};//int a[][3] = {{1,2,3},{4,5,6}};//int a[][3] = {1,2,3,4,5,6,7,8};//int a[2][3] = {0};int i,j;for(i = 0;i < 3;i++){for(j =0 ; j < 3;j++){printf("a[%d][%d] = %d\n",i,j,a[i][j]);}}printf("%p\n",&a[0][0]);printf("%p\n",&a[0]);printf("%p\n",a);printf("%p\n",&a);printf("%p\n",&a[0][0] + 1);printf("%p\n",&a[0] + 1);printf("%p\n",a + 1);printf("%p\n",&a + 1);return 0;}
2.2 二维数组的初始化和遍历
#include <stdio.h>int main(int argc, const char *argv[]){//int a[3][4];//int a[2][3] = {{4,5,6},{7,8,9}};//全部初始化//int a[2][3] = {1,2,3,4}; //按行存储,没有设置的自动补0//int a[2][3] = {{1},{2}};//int a[][3] = {{10,20},{30}};//int a[2][] = {1,2,3,4,5}; //错误写法int i,j;//外层循环控制行数//内层循环控制列数for(i = 0 ; i < 2;i++){for(j = 0 ; j < 3;j++){printf("%-5d",a[i][j]);}putchar(10);}return 0;}
三 字符数组和字符串
#include <stdio.h>int main(int argc, const char *argv[]){char ch1[] = {'h','e','l','l','o'};printf("sizeof(ch1) = %ld\n",sizeof(ch1));//字符数组的遍历int i;for(i = 0; i < sizeof(ch1)/sizeof(ch1[0]);i++){printf("%c ",ch1[i]);}putchar(10);char ch2[] = "world";printf("sizeof(ch2) = %ld\n",sizeof(ch2));printf("ch2 = %s\n",ch2);char ch3[] = {'h','e','l','l','o','\0'};printf("ch3 = %s\n",ch3);char ch4[] = "hello\0world";printf("sizeof(ch4) = %ld\n",sizeof(ch4));for(i = 0 ; i < sizeof(ch4)/sizeof(ch4[0]);i++){printf("[%c] %d\n",ch4[i],ch4[i]);}puts("---------------------------------------");char str[4][32] = {"hello","nihao beijing","hello kitty","welcome to nanjing"};int j;for(i = 0 ; i < 4;i++){for(j = 0 ; j < 32;j++){printf("%c",str[i][j]);}putchar(10);}return 0;}
3.1 字符串逆序
#include <stdio.h>int main(int argc, const char *argv[]){char str[32] = {0};printf("请输入一个字符串: ");scanf("%s",str);int i = 0,length = 0;while(str[i] != '\0'){length++;i++;}int x = 0, y = length -1;for(i = 0 ; i < length /2 ;i++){char t = str[x];str[x] = str[y];str[y] = t;x++;y--;}printf("%s\n",str);return 0;}
3.2 插入数据
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){char str[32] = {0};int num,i;char ch;printf("请输入字符串,位置,插入的元素:\n");scanf("%s%d %c",str,&num,&ch);int length = strlen(str);for(i =0 ; i < length - num +1;i++){str[length - i] = str[length -i - 1];}str[num - 1] = ch;printf("%s\n",str);return 0;}
四 字符串函数
4.1 为什么要使用字符串函数
一般字符串都是保存在一个数组里面,但是数组定义好之后,是不能整体操作的,所以我们需要借助一下字符串相关操作的函数来对字符串进行操作
#include <stdio.h>int main(int argc, const char *argv[]){char s1[] = "hello world";char s2[] = "hello world";if(s1 == s2){printf("s1 = s2\n");}else{printf("s1 != s2\n");}//数组如果没有初始化,数组下标必须写//char str[];return 0;}
4.2 常用字符串函数
4.2.1 strlen()
头文件:#include <string.h> 原型:size_t strlen(const char *s);功能:获取一个字符串的长度参数:s:要获取长度的字符串 直接传入一个字符串,或者字符数组名都可以返回值:字符串的长度
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){//strlen函数获取字符串的长度//获取的长度是这个字符串中第一\0位置之前的长度,不包括\0char s1[] = "hello world";printf("strlen(s1) =%ld\n",strlen(s1));printf("sizeof(s1) =%ld\n",sizeof(s1));char s2[] = "hello wor\0ld";printf("strlen(s2) =%ld\n",strlen(s2));printf("sizeof(s2) =%ld\n",sizeof(s2));//以下这个不是一个字符串,没有\0,所以不能用strlen来获取字符串长度,strlen会一直从首地址的位置找\0char s3[] = {'h','e','l','l','o'};printf("strlen(s3) =%ld\n",strlen(s3));printf("sizeof(s3) =%ld\n",sizeof(s3));char s4[32] = "hello world";printf("strlen(s4) =%ld\n",strlen(s4));printf("sizeof(s4) =%ld\n",sizeof(s4));return 0;}
4.2.2 strcmp()
头文件:#include <string.h> 原型:int strcmp(const char *s1, const char *s2);功能: 比较两个字符串的大小参数:s1,s2两个字符串返回值: 0: s1 = s2 <0: s1 < s2 >0: s1 > s2int strncmp(const char *s1, const char *s2, size_t n);用于比较两个字符串前n个字节是否一样
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){//strcmp比较的是\0之前的内容,跟字符串所在内存空间没有关系//char s1[32] = "hello w\0orld";//char s2[] = "hello w\0orld";char s1[] = "h";char s2[] = "hello abcdefgwhi";int ret = strcmp(s1,s2);if(ret == 0){printf("s1 = s2\n");}else if(ret > 0){printf("s1 > s2\n");}else{printf("s1 < s2\n");}int k = strncmp(s1,s2,2);if(k == 0){printf("s1 = s2\n");}else if(k > 0){printf("s1 > s2\n");}else{printf("s1 < s2\n");}return 0;}
4.2.3 strcpy()
头文件:#include <string.h> 原型:char *strcpy(char *dest, const char *src);功能: 将src字符串赋值到dest字符串中参数: dest:目的字符串 src:源字符串返回值: 返回目的字符串的首地址char *strncpy(char *dest, const char *src, size_t n);
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){char s1[32];strcpy(s1,"hello world");printf("s1 = %s\n",s1);char s2[] = "hello world";char s3[32] = "abcdefg";//strcpy将 s3中的第一个\0复制给了s2strcpy(s2,s3);printf("sizeof(s2) = %ld\n",sizeof(s2));printf("s2 = %s\n",s2);int i;for(i = 0 ; i < sizeof(s2)/sizeof(s2[0]);i++){printf("[%c] %d\n",s2[i],s2[i]);}puts("------------------------");char buf1[32] = "hello world";char buf2[32] = "abcdefghijklmnopqrsst";//strcpy(buf1,buf2);//是将第二个参数的前n个字节复制给第一个参数strncpy(buf1,buf2,7);printf("buf1 = %s\n",buf1);return 0;}
5.2.4 strcat()
头文件:#include <string.h> 原型:char *strcat(char *dest, const char *src);功能: 将src追加到dest的后面参数: dest:目的字符串 src:源字符串返回值: 追加后字符串的首地址char *strncat(char *dest, const char *src, size_t n);
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){char s1[32] ="hello wo\0rldadadjajdalsdkjaskdj"; //hello woabcdefg\0char s2[32] ="abcdefg\0higk";strcat(s1,s2);printf("s1 = %s\n",s1);return 0;}
5.2.5 自己实现strcpy函数的功能
#include <stdio.h>int main(int argc, const char *argv[]){char s1[32] = "welcome to nanjing";char s2[32] = "hello world";int i = 0;while(s2[i] != '\0'){s1[i] = s2[i];i++;}s1[i] = s2[i];printf("s1 = %s\n",s1);return 0;}
六 指针概念
6.1 指针的用途
使用程序简洁,紧凑,高效有效地表示复杂的数据结构动态分配内存得到多于一个函数的返回值
当程序中定义一个变量之后,程序就会为这个变量在内存中开辟内存空间,我们内存中每一个字节的空间都有一个编号,将这个编号称之为地址,地址也叫做指针
在不影响理解的情况,有时对地址,指针,指针变量不区分,通称指针
#include <stdio.h>int main(int argc, const char *argv[]){//int a = 1;//int *pa = &a;printf("int* = %ld\n",sizeof(int *));printf("char* = %ld\n",sizeof(char *));printf("double* = %ld\n",sizeof(double *));printf("float* = %ld\n",sizeof(float *));printf("long* = %ld\n",sizeof(long *));int a = 1;char ch = 'a';//int *pc = &ch; //类型不兼容char *pch = &ch;//ch = 'x';*pch = 'x'; //等价于ch = 'x'printf("ch = %c\n",ch);printf("ch = %c\n",*pch);int *pa = &a;printf("%p\n",pch);printf("%p\n",pa);printf("%p\n",pch + 1); //不同类型的指针,步长不一样printf("%p\n",pa + 1);return 0;}
6.2指针变量的运算
指针运算的种类是有限的,它只能进行算术运算,关系运算和赋值运算
6.2.1 算术运算符
+: px + n 指针向地址大的方向移动n个数据 -: px - n 指针向地址小的方向移动n个数据++: px++ 指针向地址大的方向移动1个数据--: px++ 指针向地址小的方向移动1个数据
指针变量加减,表示指针变量向地址大或小的方向移动N个操作空间,两个指针变量相减,表示两个地址之间有多少个操作空间(多少个元素)
注意,两个指针做运算,必须是同类型的,类型不同没有任何意义。
后置++优先级高于前置++后置++结合律从左往右前置++和*优先级相同,结合律从右往左
#include <stdio.h>int main(int argc, const char *argv[]){int arr[6] = {1,3,5,8,9,10};int *p1 = arr;printf("*p1 = %d\n",*p1);p1++;int *p2 = p1++;printf("*p1 = %d,*p2 = %d\n",*p1,*p2);printf("p1 - p2 = %ld\n",p1 - p2);int y = *p1; //取值printf("y = %d\n",y);y = ++*p1;printf("y = %d\n",y);y = (*p1)++;printf("y = %d\n",y);y = *p1++; //赋值完成后,指针px加1printf("y = %d\n",y);printf("*p1 = %d\n",*p1);/*y = ++*p1++; //赋值完成后,指针px加1printf("y = %d\n",y);printf("*p1 = %d\n",*p1);*/return 0;}
6.2.2 关系运算符
两指针之间的关系运算符表示他们指向的地址位置之间的关系,指向地址大的指针大于指向地址小的指针
具有不同数据类型的指针之间的关系运算没有意义,指向不同数据区域的数据两个指针之间,关系运算符也没有意义。
指针与一般整数变量之间的关系运算也没有意义,但是可以和零进行等于或者不等于的关系运算,判断指针是否为空,一般与NULL
6.2.3 赋值运算
指针变量直接可以直接赋值,但是不能将一个整数赋值给指针变量,因为没有开辟空间
6.2.4 练习:输入一个字符串,将字符串的元素翻转
要求:定义两个指针,分别保存起始位置和末尾位置的字符,然后通过交换的方式实现。
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){char str[32] = {0};gets(str);printf("反转之前的字符串:%s\n",str);char *p = NULL,*q = NULL;char tmp;p = &str[0];q = &str[strlen(str) - 1];#if 0while(p < q){tmp = *p;*p = *q;*q = tmp;p++;q--;}#endiffor(;p < q;p++,q--){tmp = *p;*p = *q;*q = tmp;}printf("反转之后的字符串:%s\n",str);return 0;}
七 指针和一维数组
#include <stdio.h>#include <string.h>int main(int argc, const char *argv[]){int a[5] = {1,2,3,4,5};int *p = a;int i;for(i = 0 ; i < 5;i++){//printf("%d ",a[i]);printf("%d ",*(p+i));}putchar(10);char *s = "helloworld";char str[32] ="hello nanjing";s = str;//printf("%s\n",s);for(i = 0 ; i < 10;i++){printf("%c",s[i]);}putchar(10);return 0;}
练习1:通过指针自己实现strlen函数的功能
#include <stdio.h>int main(int argc, const char *argv[]){char buf[32] = {0};printf("请输入一个字符串:\n");gets(buf);char *p = buf;int i;while(*p != '\0'){p++;i++;}printf("strlen(buf) = %d\n",i);return 0;}
练习2: 通过指针实现strcpy函数的功能
#include <stdio.h>int main(int argc, const char *argv[]){char s1[] = "helloworld!";char s2[] = "abcdefghijk";char *p = NULL,*q = NULL;p = s1;q = s2;while(*q != '\0'){*p = *q;p++;q++;}*p = *q;printf("s1 = %s\n",s1);return 0;}