字符输出
ascII码就是字符,字符就是码
int main(void) {
//输出字符A
printf("%c\n",'A');
printf("%d\n",'A');//65 ascII码
printf("%c",65);//A
//输出字符的另一个方法
putchar('\n');
putchar('a');
return 0;
}
int main(void) {
char a = 'a';
printf("%c\n", a);//a
printf("%d\n", a);//97
a = 65;
printf("%c", a);//A
return 0;
}
char占一个字节,256个数
表示范围:
有符号:-128~127(-27~27-1),
无符号:0~255(0~2^8)
int main(void) {
char a = 'A';
printf("%u,%u\n", sizeof a, sizeof(char));//1,1
return 0;
}
字符的输入
scanf的含义
scanf的含义是:从缓冲区拿数据,我们输入空格的时候,内存是存的是空格,最后回车的时候会存回车\n。
所以下面两个scanf一次输入,跟一个scanf输入两个数效果一样。他不是调起平台,而是从平台拿数据。
int main(void) {
//输入
int d, c;
scanf("%d", &d);
scanf("%d", &c);//两个
printf("%d,%d", d, c);//1,2
return 0;
}
image.png
字符输入
int main(void) {
//输入
char c, d;
scanf("%c", &c);
scanf("%c", &d);
printf("%c,%c", c, d);
return 0;
}
当我输入一个字符,回车的时候,结果是:d成了一个换行。
分析:s是一个字符,然后换行\n也是一个字符,sancf从缓冲区拿数据所以打印d是\n。
输入字符的时候,输入前后都不要有空格回车什么的,要不然从缓冲区取数据的时候,会取出你不想要的东西。或者在输入字符前,把缓冲区清空。
image.png
清空缓冲区
- 在输入字符之前setbuf(stdin, NULL);清除缓冲区
- while((c=getchar())!='\n'&&c!=EOF);
int main(void) {
//输入
char c, d;
scanf("%c", &c);
setbuf(stdin, NULL);
scanf("%c", &d);
printf("%c,%c", c, d);
return 0;
}
image.png
int main(void) {
//输入
char c, d;
c = getchar();
while ((c = getchar()) != '\n' && c != EOF);
c = getchar();
printf("%c,%c", c, d);
return 0;
}
scanf_s
int main(void) {
//输入
char c, d;
int a;
char s[10];
scanf_s("%c", &c);
scanf_s("%c", &c, 1);//要写1
scanf_s("%c%d", &c, 1, a);
scanf_s("%s", s, 9); //要写9
printf("%c,%c", c, d);
return 0;
}
getchar()
一次读一个
int main(void) {
//输入
char c, d;
int a;
char s[10];
c = getchar();
printf("%c", c);
return 0;
}
_getch()/getch()
随输入随读取,不需要回车确定吗,头文件conio.h
输入直接进缓冲区,控制台不显示。
大小写字母转换
数组字符与字符
字符'0': AscII码48
int main(void) {
//大小写转化
char c;
while (1) {
scanf("%c", &c);
if (c >= 65 && c <= 90) {//大写字母
printf("%c", c+32);
} else if (c >= 97 && c <= 122) {
printf("%c", c-32);
} else if (c == '\n') {
break;
}
}
return 0;
}
字符数组
一维字符数组字符大小:1*数组长度 sizeof(char[5])
int main(void) {
//字符数组
//初始化部分数组元素,其他默认为0
char arr[5] = {'a', 'b', 'c', 'd', 'e'};
for (int i = 0; i < 5; ++i) {
printf("%c",arr[i]);//abcde
}
printf("\n");
char arr2[5] = {'a', 'b', 'c'};
for (int i = 0; i < 5; ++i) {
printf("%c",arr2[i]);//abc
printf("%d,",arr2[i]);// 97,98,99,0,0,
}
return 0;
}
指针取数组元素
字符数组,要用for循环一个一个的字符输出,不能用printf("%s,", arr4)
int main(void) {
//字符数组
//初始化部分数组元素,其他默认为0
char arr[5] = {'a', 'b', 'c', 'd', 'e'};
char *p = &arr;
//利用指针遍历数组
for (int i = 0; i < 5; ++i) {
printf("%c,", p[i]);//a,b,c,d,e,
printf("%c,", *(p + i));//a,b,c,d,e, //*的优先级高于+,所以加括号
printf("%c,", *p++);//a,b,c,d,e, //* 和++ 优先级一样,结合性:自右向左运算
}
return 0;
}
字符串
概念:以"\0"(0)结尾的字符数组
"\0"就是数字0,AscII码的第一个.如下:
char arr[5] = {'a', 'b', 'c', 'd', '\0'};
char arr1[5] = {'a', 'b', 'c', 'd', 0};
char arr2[5] = {'a', 'b', 'c'};
char arr3[5] = {'a', 'b', 'c', '\0'};
这就是字符串啦
原理:从给定的字符串地址开始,一个个的输出,遇到"\0"结束,没有"\0"停不下来,越界也不停止
int main(void) {
//字符数组,要用for循环一个一个的字符输出,不能用printf("%s,", arr4)
//字符数组
char arr4[5] = {'a', 'b', 'c', 'd', '5'};
//字符串
char arr[5] = {'a', 'b', 'c', 'd', '\0'};
char arr1[5] = {'a', 'b', 'c', 'd', 0};
char arr2[5] = {'a', 'b', 'c'};
char arr3[5] = {'a', 'b', 'c', '\0'};
//原理:从给定的字符串地址开始,一个个的输出,遇到"\0"结束,没有"\0"停不下来,越界也不停止
//所以字符数组,要用for循环一个一个的字符输出
printf("%s,", arr);//abcd,
char arr5[5] = {'a', 'b', 0, 'd', '5'};
printf("%s,", arr5);//ab, //打印截止到0
char arr6[5] = {'a', 'b', 'f', 'd', '\0'};
printf("%s,", &arr[2]);//cd,, //从给定到首地址打印
//字符串的专有输出,自带换行
puts(arr);//abcd
puts(&arr[2]);//cd //
return 0;
}
应用将字符串abcd 以字符abcd打印出来
void outString(char *str1);
int main(void) {
char arr4[5] = {'a', 'b', 'c', 'd', '\0'};
outString(arr4);
return 0;
}
//遍历字符串
void outString(char *str1) {
for (str1; *str1 != '\0'; str1++) {
// 下面两种都行
putchar(*str1);//abcd
printf("%c",*str1);//abcd
}
}
字符串的声明方式
- 有元素个数
char arr[5] = {'a', 'b', 'c', 'd', '\0'};
char arr1[5] = {'a', 'b', 'c', 'd', 0};
char arr2[5] = {'a', 'b', 'c'};
char arr3[5] = {'a', 'b', 'c', '\0'};
//注意
char str[5]; //声明之后,只能一个一个的赋值或者循环去赋值
str[0]='a';
str[1]='b';
str[2]='c';
str[3]='d';
str[4]='\0';
- 无元素个数
不指定元素个数,就一定要进行初始化,一定要手写"\0"
char arr[]={'a','b','c','\0'}
常量字符串"hello"
- 常量字符串不能被修改
int main(void) {
char *p = "hello xiao";
//可以修改指针的指向,
p="w222";
printf("%s", p);//w222
printf(p);//w222 打印字符串另一个方法 // printf("hello xiao")
//!!但是 下面修改值不能被修改,下面是错误的❌
*p="wqqq";//❌
*p='weee';//❌
return 0;
}
- 常量字符串自带'\0'
- char *p = "hello xiao";
printf("%s", p);
int main(void) {
printf("%s", "hello");//hellohello
char *p = "hello xiao";
printf("%s", p);//xiao
return 0;
}
用常量字符串初始化数组
int main(void) {
//初始化数组,这两种写法只能在初始化的时候用,赋值看下面
//方法一
char str[20] = "hellp xiao"; //元素个数要大于等于字符串的长度
printf("%s\n", str);//hellp xiao
//方法二
char str2[] = "hellp xiao";//不写长度,系统计算长度,然后在栈区申请空间
str2 = "qwe";//❌
str[10] = "qwe";❌
return 0;
}
char str[20] = "hello xiao"; 解读
- 常量字符串是自带/0的,所以,"hello xiao"的长度是11(空格也别落下)
-
如下图,常量字符串初始化数组时,常量"hello xiao"存在常量区,而str存在栈区,当"hello xiao"赋值给str后,会依次把值赋值到栈区。所以当我们操作str的时候(比如str[0]='w'),是操作的栈区的内存,是可以修改的。但是在字符串常量中:char *p = "hello xiao"; 因为p直接指向的是"hello xiao"常量,所以,是不能修改他的值的*p="wqqq";❌
image.png
字符数组的赋值
int main(void) {
char str[20] = "hello";
printf("%s\n", str);//hello
//方法一 用字符常量
char *p = "www";
int i = 0;
for (; *p != '\0'; ++p) {
str[i] = *p;
i++;
}
printf("%s\n", str);//wwwlo,
// 分析原因:因为在i='\0'的时候没有赋值给str,把'\0'赋值给他最后一项就好了
//加完 '\0'之后 str="www\0o"
str[i] = '\0';
printf("%s\n", str);//www
//方法二
//用数组的话
char str1[4] = "www";
//遍历数组str1
//剩下的跟上面一样
return 0;
}
字符串操作函数
strcpy:复制函数
int main(void) {
char str[20] = "hello";
char str1[] = "xiao";
char *p = str1;
//复制函数,第一个函数一定要是栈区内存的
strcpy(str, str1);// 可以写成strcpy(str, p);
printf("%s", str);//xiao
return 0;
}
strncpy() 复制几个字符
int main(void) {
char arr[] = "abcde";
strncpy(arr, "hhh", 3);
printf("%s", arr);//hhhde
}
字符串的输入
scanf("%s\n", str); 不能空格
- 不能读空格,注意%c会把空格读出来,而%s会把空格当作凤娥
int main(void) {
char str[20];
scanf("%s\n", str);
printf("%s", str);
}
image.png
缓冲区的数据会一个一个读,所以下面这个例子,当输入qwe qq,scanf %s看到空格就不取数据了(遇到空格scanf会把'\0'加到str里面去,所以str后缀就不是乱码了)。但是qq还在缓冲区里,所以下一次输入的时候,scanf取之会把qq取出来,aa在缓冲区
int main(void) {
char str[20];
scanf("%s\n", str);
printf("%s", str);
scanf("%s\n", str);
printf("%s", str);
}
image.png
gets 可以读空格
int main(void) {
char str[20];
gets(str);
printf("%s", str);
}
image.png
中午与字符 一个汉子占两个字节
一个char能表示(0255/-128127)256个数,这256个数被AscII码占有了,所以中文等其他数字就要用>255的数字表示,即大于1的字节。
一个汉子占两个字节,用一个char肯定装不了,要用两个cahr,也就是字符数组,然后末尾加个"\0",他就变成字符串了。
char str[3]="晓",输printf("%s",str); 或者printf("%c%c",str[0],str[1])//%c一定要挨在一起。
int main(void) {
char str[3] = "晓"; //双引号
printf("%s\n", str);//晓
printf("%c%c\n",str[0],str[1]);//%c%c
return 0;
}
如何打印汉子数字码
- 汉子国标码查询
- printf("%x%x\n",str[0],str[1]); %x%x
- 对应的十进制的打印:
int main(void) {
char str[3] = "晓"; //双引号
printf("%s\n", str);//晓
//方法一
//打印
printf("%x%x\n", str[0], str[1]);//%c%c 这是国际码ffffffe6ffffff99
//方法二
printf("%x\n", *(short *) str);//ffff99e6 正常顺序是 e699,
// 但是直接转成short之后,因为内存从高地址到低地址读,所以成了99e6
//所以得让str[0]和str[1]交换
char temp;
temp = str[0];
str[0] = str[1];
str[1] = temp;
printf("%x", *(short *) str);//ffffe699,这个就是编码了
//❗️注意:这个是无符号的
unsigned short a = *(short *) str;
return 0;
}
字符串其他的操作函数
strlen 求字符数
size_t len = strlen(const char *__s):求字符数
int main(void) {
char *p = "12345"; //双引号
char str[] = "12345";
//size_t 就是unsigned int,他只不过是个类型重命名
size_t len = strlen(p);//size_t len = strlen(str);
printf("%d\n", len);//5 strlen求对是字符数,不算'\0'
return 0;
}
int strcmp(const char *string1,const char *string2)
//比较两个字符串第一个不同的字符
//string1大:返回值>0,
//string2大:返回值<0,
//相等,返回值=0
int strcmp(const char *string1,const char *string2)
int main(void) {
int a = strcmp("abcd", "abceaaa");
printf("%d",a);//-1
return 0;
}
int strncmp(const char *string1,const char *string2,size_t count)
比较前count个字符
strcat 字符串末尾拼接
int main(void) {
char str[20] = "abc";
strcat(str, "abce");
printf("%s", str);//abcabce
return 0;
}
strncat 把第n个参数的前2个字符拼接到第一个参数末尾
int main(void) {
char str[20] = "abc";
//把第二个参数的前2个字符拼接到str上
strncat(str, "abce",2);
printf("%s", str);//abcab
return 0;
}
atoi 字符串转化成数组,相当于java中的integer.parseint
int main(void) {
int a = atoi("1");
int b = atoi("3333");
printf("%d,%d", a,b);//1,3333
return 0;
}
itoa
int main(void) {
char str[20]={0};
//第三个参数是几进制的意思
itoa(235,str,2);
printf("%s", str);//先转化成2进制的数,然后再转化成字符串
return 0;
}
sprintf
int main(void) {
char str[20] = {0};
//把第二个参数以字符串的形式"12,v,12.300000"赋值给第一个参数str
sprintf(str, "%d,%c,%f", 12, 'v', 12.3f);
printf(str);//12,v,12.300000
return 0;
}
转义字符和转换字符
转义字符:\
转换字符:%
image.png image.png
image.png
- \字母:占一个字节
int main(void) {
printf("%u\n",strlen("\n"));//1//转义字符换行
printf("%u\n",strlen("\w"));//1//不是转义字符
return 0;
}
- \数字 :代表一个字节
分为:
\+数字 : \123
8进制。数字位数限制:1~3位。数字值限制:0~255(8进制是0~377)
\+0+数字:
8进制。数字位数限制:1~2位。数字值限制:0~63(8进制是0~77)
\+x+数字:
16进制。数字位数限制:1~2位。数字值限制:0~255(16进制是0~ff)
在上面的范围内,是一个字节,超过上面的范围就不一定咯。
测试:
int main(void) {
//分析:因为\+数字是8进制的,8进制最高位数字是7
//系统会把\58 看成是\5和8,所以是2
printf("%u\n", strlen("\57"));//1
printf("%u\n", strlen("\58"));//2
//因为\+数字 超过了377,所以他从末尾减一位,分成\37和8
//注意:如果超过的很大,直接报错,比如\400
printf("%u\n", strlen("\378"));//2
//分析:因为\0+数字是8进制的,8进制最高位数字是7
printf("%u\n", strlen("\018"));//2
//xff一个字符,w是一个字符,因为w不是16进制的,所以不报错
printf("%u\n", strlen("\xffw"));//2
//报错,超过两个了
printf("%u\n", strlen("\xfff"));//2
return 0;
}
字符串数组与二维字符数组
- 字符串数组
每一个元素都是这个字符串的首地址。
int main(void) {
//字符串数组
//每个元素都装着字符串的首地址,每个元素都是char *,
//即:每个元素都是指向字符串首地址的指针。
char *str[3] = {"abd", "asdss", "wlekdc"};
//读取:
for (int i = 0; i < 3; ++i) {
printf("%s,", str[i]);//abd,asdss,wlekdc,
}
printf("\n");
//修改:
//str[0]可以指向新的字符串
str[0] = "123";
printf(str[0]);//123
printf("\n");
//读字符串常量中的某一个字符
printf("%c", *str[1]);//"asdss"中的a
//注意因为是字符串常量,所以无法修改他的值。
*str[1]='w';//这个是错的❌.常量无法修改
return 0;
}
- 二维字符数组
lude <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
//可以用字符串初始化,也可以用字符初始化
//tr[2][4] 2个元素,,每个元素4个字节数
char str[2][4] = {"adc", "12"};//因为字符串默认有一个'\0',所以最多就是三个字节数/
//读取字符串
for (int i = 0; i < 2; ++i) {
printf("%s ", str[i]);//adc 12
}
//读取字符
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 4; ++j) {
if (str[i][j] != '\0') {
printf("%c ", str[i][j]);//a d c 1 2
}
}
}
//注意:
//这个是常量区的adc 12赋值到栈区的str中了,所以str操作的是栈区的空间
//这个类似与 char str2[4]="abc" //把常量区里面的abc赋值到栈区的str2中
//所以,跟char *str[3]={"acd","ss","qwxa"}不同的是,他可以修改元素任意的字符,修改的是栈区的内容
str[0][0] = 'n';
printf("%s",str[0]);//ndc
return 0;
}
网友评论