源码 补码 反码
数组定义,初始化,使用,随机数
找最大数,逆置,冒泡排序,
scanf 输入字符串
字符串处理
字符串溢出等问题
scanf()
gets()
puts()
fputs()
strlen()
strcat()
strncat()
strcmp()
strncmp()
strchr()
strstr()
strtok()
atoi()
atof()
atol()
C 字符串数组
定义数组
遍历输出数组每个元素的值
//GCC 编译方式: C:\MinGW\project>gcc -std=c99 main.c //编码环境 GBK #include <stdio.h> int main(){ int array[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}; //遍历二维数组,并打印 for(int i=0;i< 3;i++){ for(int j=0;j<4;j++){ printf("array[%d][%d]=%d\n",i,j,array[i][j]); } } /* 输出 : array[0][0]=0 array[0][1]=1 array[0][2]=2 array[0][3]=3 array[1][0]=4 array[1][1]=5 array[1][2]=6 array[1][3]=7 array[2][0]=8 array[2][1]=9 array[2][2]=10 array[2][3]=11 */ }
字符数组多种初始化方式
研究\0 对字符串数组的影响
#include <stdio.h> int main(){ //字符串的初始化 //char str[100] ; //定义一个字符串 //char str[100] = {‘h‘,‘e‘,‘l‘,‘l‘,‘o‘}; //定义一个字符串,并初始化 char str[100] = "hello"; //多种初始化 str[0] = ‘H‘; str[1] = ‘e‘; str[2] = ‘\0‘; //遇到\0,字符串就结束了 str[3] = ‘l‘; str[4] = ‘o‘; printf("%s\n",str); //字符串就是以\0结尾的数组 //输出 He printf("str =%d\n",sizeof(str)); //输出 str =100 }
看看字符串数组\0后面是什么东西
#include <stdio.h> int main(){ //固定字符数组大小,研究字符串初始化后是什么东西 char str[10] = "Hello"; printf("str =%d\n",sizeof(str)); //输出 str2 =10 printf("str[4] char=>%c HEX=>%x\n",str[4],str[4]); printf("str[5] char=>%c HEX=>%x\n",str[5],str[5]); printf("str[6] char=>%c HEX=>%x\n",str[6],str[6]); printf("str[7] char=>%c HEX=>%x\n",str[7],str[7]); //输出: // str[4] char=>o HEX=>6f // str[5] char=> HEX=>0 // str[6] char=> HEX=>0 // str[7] char=> HEX=>0 }
显示字符串长度大小
#include <stdio.h> int main(){ //打印字符数组大小 char str1[] = "Hello"; printf("str1 =%d\n",sizeof(str1)); // 输出 str1 =6 }
修改字符串的内容
#include <stdio.h> int main(){ //修改字符串内容 char str3[99]="Hello World!"; printf("%s",str3); printf(str3); str3[4]=‘A‘; printf(str3); //输出 Hello World!Hello World!HellA World! }
逆置数组
#include <stdio.h> int main(){ char str3[99]="Hello World!"; int low=0; int high=11; //注意上面的那个字符,11位之后就是\0了 int tmp_var; while(low<high){ tmp_var =str3[low]; str3[low] =str3[high]; str3[high] =tmp_var; low++; high--; } printf(str3); //输出: //数组逆置: //!dlroW AlleH }
显示GBK编码的汉字编码
//GBK 编码 #include <stdio.h> int main(){ char str4[100] ="你好 世界"; printf("\n%s\n",str4); for(int i=0;i<13;i++){ printf("%x\n",str4[i]); } } /* C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe 你好 世界 ffffffc4 ffffffe3 ffffffba ffffffc3 20 ffffffca ffffffc0 ffffffbd ffffffe7 0 0 0 0 */
显示GBK编码的汉字
//GBK 编码 #include <stdio.h> int main(){ //用GBK编码显示 汉字 char str5[100]; str5[0]=0xc4; str5[1]=0xe3; str5[2]=0; printf(str5); //输出 你 }
scanf函数漏洞演示:
遇到空格一定会对scanf有影响
#include <stdio.h> int main(){ char a[3]={0}; char b[3]={0}; scanf("%s",a); scanf("%s",b); printf("==========\n"); printf("%s\n",a); printf("%s\n",b); } 测试: C:\MinGW\project>gcc -std=c99 str.c 正常输入: C:\MinGW\project>a.exe 12 qw ========== 12 qw
溢出测试1
C:\MinGW\project>a.exe 12 qwqwqwwqwqw ========== wqwwqwqw qwqwqwwqwqw 溢出测试2 C:\MinGW\project>a.exe 123 qwerty ========== rty qwerty
scanf 溢出的原因:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(){ char a[10]={0}; char b[300]={0}; int c[10]; printf("a address %p\n",a); printf("b address %p\n",b); printf("c address %p\n",c); system("pause"); //程序等待在这里 } /* C:\MinGW\project>gcc str.c C:\MinGW\project>a.exe a address 0028FF16 b address 0028FDEA c address 0028FDC0 请按任意键继续. . . */
scanf会把接受到的值,在内存从开始存,不会去管是否已经溢出
这样会导致覆盖其他变量的数值
可以看出,程序已经出错
gets可以解决scanf的无法记录空格的问题 #include <stdio.h> int main(){ char a[30]={0}; gets(a); printf(a); } C:\MinGW\project>a.exe hello world ! hello world !
但是依然会缓冲区溢出
#include <stdio.h> int main(){ char a[3]={0}; char b[3]={0}; gets(a); gets(b); printf("%s\n",a); printf("%s\n",b); } C:\MinGW\project>a.exe 123456789 qwertyuioop rtyuioop qwertyuioop C:\MinGW\project>
fgets解决了空格 缓存区溢出问题
#include <stdio.h> int main(){ char a[5]={0}; // fgets(a,5,stdin); fgets(a,sizeof(a),stdin); printf("%s\n",a); } C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe 12 e343 423 12 e
puts会在输出后面加入一个\n
#include <stdio.h> int main(){ char a[]="Hello world !"; puts(a); printf("=================="); printf(a); printf("=================="); } C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe Hello world ! ==================Hello world !==================
fput函数,可以代替printf
#include <stdio.h> int main(){ char a[]="Hello world !"; fputs(a,stdout); } C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe Hello world !
对输入的字符,逆置
#include <stdio.h> int main(){ char a[99]={0}; scanf("%s",a); printf("%s \n",a); //strlen 返回是数组有效长度,不包含\0 //获取字符串真实长度,相当于strlen int i = 0; while(a[i] != ‘\0‘) i++; //逆置字符数组 int low = 0; int high= i-1; //因为字符数组有一个‘\0‘ char tmp; while(low < high){ tmp = a[low]; a[low] = a[high]; a[high]= tmp; low++; high--; } printf("%s \n",a); } C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe qwertyuio09876 qwertyuio09876 67890oiuytrewq C:\MinGW\project>a.exe 你好 你好 strlen 4 sizeof 99 煤隳
字符串追加:
注意:可能导致溢出
#include <stdio.h> #include <string.h> int main(){ char a[99]={0}; char b[300]={0}; scanf("%s",a); scanf("%s",b); strcat(a,b); //把b追加到a后面,a要足够大 printf("a+b=%s\n",a); } C:\MinGW\project>a.exe 123 abc a+b=123abc
手动实现strcat
#include <stdio.h> #include <string.h> int main(){ char a[99]={0}; char b[300]={0}; scanf("%s",a); scanf("%s",b); //strcat(a,b); //把b追加到a后面,a要足够大 //手写一个strcat int lena = strlen(a); int lenb = strlen(b); for(int i = lena;i < lena + lenb;i++){ a[i] = b[i-lenb]; } printf("a+b=%s\n",a); } C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe 123 abc a+b=123abc
strncat指定追加个数
#include <stdio.h> #include <string.h> int main(){ char a[10]={0}; char b[300]={0}; scanf("%s",a); scanf("%s",b); strncat(a,b,sizeof(a)-strlen(b)-1); //留一个‘\0‘ printf("a+b=%s\n",a); } /* C:\MinGW\project>gcc -std=c99 str.c C:\MinGW\project>a.exe 12345 qwertyuiop a+b=12345qwertyuiop */
1 整数在计算机内部的存储方式
1.1 原码
将最高位做为符号位(0代表正,1代表负),其余各位代表数值本身的绝对值
+7的原码是00000111 -7的原码是10000111 +0的原码是00000000 -0的原码是10000000 |
1.2 反码
一个数如果值为正,那么反码和原码相同
一个数如果为负,那么符号位为1,其他各位与原码相反
+7的反码00000111 -7的反码11111000 -0的反码11111111 |
1.3 补码
原码和反码都不利于计算机的运算,如:原码表示的7和-7相加,还需要判断符号位。
正数:原码,反码补码都相同
负数:最高位为1,其余各位原码取反,最后对整个数 + 1
-7的补码:= 10000111(原码) 111111000(反码) 11111001(补码) +0的补码为00000000 -0的补码也是00000000 |
补码符号位不动,其他位求反,最后整个数+ 1,得到原码
用补码进行运算,减法可以通过加法实现 |
7-6=1 7的补码和-6的补码相加:00000111 + 11111010 = 100000001 进位舍弃后,剩下的00000001就是1的补码 |
-7+6 = -1 -7的补码和6的补码相加:11111001 + 00000110 = 11111111 11111111是-1的补码 |
2 数组
内存连续,并且是同一种数据类型的变量,C语言的数组小标好是从0开始的,到n-1.
2.1 一维数组定义与使用
类型变量名称[数组元素的个数];
2.2 数组在内存的存储方式
在内存当中是连续的内存空间地址。
2.3 一维数组初始化
int array[10] = {0};//将数组所有元素都初始化为0
int array[10] = {0,1,2,3,4,5,6,7,8,9}
数组中找最大值思路
数组中找第二大值思路
逆置数组思路
测量楼宇高度的说明
测量地球太阳距离的说明
测量太阳木星距离的说明
2.4 二维数组定义与使用
intarray[3][4];//12个元素的二维数组
2.5 二维数组初始化
int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; |
3 字符串与字符数组
3.1 字符数组定义
char buf[100];
对于C语言字符串其实就是一个最后一个元素为’\0’的char数组.
3.2 字符数组初始化
char buf[] = “hello world”;
3.3 字符数组使用
3.4 随机数产生函数rand与srand
头文件stdlib.h
#include<time.h> int t = (int)time(NULL); srand(t); for (int i = 0; i < 10; i++) { printf("%d\n", rand()); } |
3.5 用scanf输入字符串
char buf[100] = {0};
scanf(“%s”, buf);
scanf("请输入i的值%d",&i);
3.6 字符串的结束标志
3.7 字符串处理函数
3.7.1 gets
gets没有解决缓冲区溢出的问题.
3.7.2 fgets函数
gets函数不检查预留缓冲区是否能够容纳用户实际输入的数据。多出来的字符会导致内存溢出,fgets函数改进了这个问题。
由于fgets函数是为读取文件设计的,所以读取键盘时没有gets那么方便
char s[100] = { 0 }; fgets(s, sizeof(s), stdin); |
3.7.3 puts函数
puts函数打印字符串,与printf不同,puts会在最后自动添加一个’\n’
char s[] = "hello world"; puts(s); |
3.7.4 fputs函数
fputs是puts的文件操作版本,
char s[] = "hello world"; fputs(s, stdout); |
3.7.5 strlen,字符串长度
strlen返回字符串的长度,但是不包含字符串结尾的’\0’
char buf[10]
sizeof(buf);//返回的是数组buf一共占据了多少字节的内存空间.
3.7.6 strcat,字符串追加
char str1[100];
char str2[100];
strcat(str1, str2);//把str2追加到str1的后面
str1一定要有足够的空间来放str2,不然会内存溢出.
3.7.7 strncat,字符串有限追加
strncat(str1, str2, sizeof(str1) –strlen(str1) - 1);
3.7.8 strcmp,字符串比较
strcmp(a, “str”);//如果两个参数所指的字符串内容相同,函数返回0
3.7.9 strncmp,字符串有限比较
strncmp(str, “exit”, 4);
3.7.10 strcpy字符串拷贝
strcpy(str, “hello world”);//存在溢出的问题,
3.7.11 strncpy字符串有限拷贝
strcpy(str, “hello world”, 7);
3.7.12 sprintf,格式化字符串
printf是向屏幕输出一个字符串
sprintf是向char数组输出一个字符串,其他行为和printf一模一样
sprintf也存在缓冲区溢出的问题
3.7.13 strchr查找字符
strchr(str, ‘c’);
返回值是字符’c’在字符串str中的位置
3.7.14 strstr查找子串
3.7.15 strtok分割字符串
字符在第一次调用时strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL每次调用成功则返回指向被分割出片段的指针
char buf[] = "[email protected]@igk"; char *p = strtok(buf, "@");; while (p) { printf("%s\n", p); p = strtok(NULL, "@"); } |
3.7.16 atoi转化为int
3.7.17 atof转化为float
3.7.18 atol转化为long
作业说明:
不可以用任何已有的函数,完全自己写代码,完成十进制字符串转化为十进制的整数
作业思路: