字符数组的传递
#include<stdio.h>
void print(char c[]) {
int i = 0;
while (c[i]) {
printf("%c", c[i]);
i++;
}
}
int main() {
char c[10] = "hello";
print(c);//这里的参数是实参,而print里的参数叫做形参
}
主方法通过传参给print方法执行语句。主方法main中print©的c是实参,而print方法里的参数叫做形参。
while(c[i])其实等同于while(c[i]!=0)或者while(c[i]!=’\0’),因为c[i]等于0是判定为假
其实%s的输出原理就跟print方法差不多,遇到’\0’就输出。
gets与puts函数
gets和puts是用于输入和输出字符串的
而scanf、printf可以输入输出整形数、浮点数、字符、字符串(scanf可以通过输入字符数组里的字符组成字符串)
那么它的应用场景在哪里呢?
因为%s使用scanf输入字符串时候,会忽略空格和回车。因此我们需要输入一些带空格的语句时就会实现不了,例如:hello world
这时候gets与puts函数就此诞生了。
*其实gets(char str)中char * 是字符指针(传入的参数是字符指针),而我们平常定义的字符数组 char c[]里的变量名存的时起始地址其实类型就是字符指针(因为在定义字符数组的时候,编译器给变量名内部存了一个值,其类型就是字符指针)
#include<stdio.h>
int main() {
char c[20];//这里的c存的时起始地址其实类型就是字符指针
gets(c);
puts(c);//等价与printf("%s",c)
return 0;
}
注意:回车是读取不了的,读取到\n是就判定为输入结束
常看内存后发现gets在遇到\n之后不会存储\n,而是将其翻译为字符’\0’
str系列字符串操作函数
str系列字符串操作函数主要包括strlen、strcpy、strcmp、strcat等。
strlen函数用于统计字符串长度
strcpy函数用于将某个字符串复制到字符数组中
strcmp 函数用于比较两个字符串的大小
strcat函数用于将两个字符串连接到一起
用法为:
下面一一演示
strlen
strlen函数用于统计字符串长度
#include<stdio.h>
int main() {
char c[20] = "zjm here";
printf("字符数组c的长度为:%d\n", strlen(c));
return 0;
}
strcpy
strcmp 函数用于比较两个字符串的大小
把后面的字符指针的值赋值给前面字符指针。
#include<stdio.h>
int main() {
char c[20] = "zjm here";
char d[20];
printf("字符数组c的长度为:%d\n", strlen(c));
strcpy(d, c);
printf("字符数组d的内容为:%s\n", d);
return 0;
}
定义一个字符数组d,把字符数组c的内容复制到d上
strcmp
strcmp 函数用于比较两个字符串的大小
规则:比较的是两个字符的ACSII值,如果前面的大于后面的返回1;相等则返回0;后面的大于前面返回-1
#include<stdio.h>
int main() {
int ret=strcmp("how","hello");
printf("字符比较返回的值为:%d\n", ret);
return 0;
}
看上面的程序,返回的值是1还是-1呢?
很多人第一反应是:那不废话吗?hello比how长肯定是-1啊,其实结果是1。
解析:比较的是两个字符的ACSII值。比如上述程序中,how与hello比较第二个字符的时候o的acsii值已经大于h了,因此how肯定大于hello。
就好像120肯定大于119.99999一样,虽然你后者长,但是始终没我前者大。
strcat
strcat函数用于将两个字符串连接到一起
注意:是吧后面的字符串拼接到前面的字符串,所以要注意前者是否有足够的空间容纳。
#include<stdio.h>
int main() {
char c[20] = "zjm here";
char d[20];
strcpy(d, c);
strcat(c, d);
puts(c);
return 0;
}
指针
指针是C语言最难的知识点,令所有新手小白都闻风丧胆,我虽然又学过C语言,但是对于指针我感觉还是一窍不通何况太久没碰了所以跟小白没差别,接下来我们就来学习一下指针。
其实指针的作用就是保存地址
#include<stdio.h>
int main() {
int a = 5;
}
就比如这张图,右边的内存中。我们整形变量a的值5确实存入了内存的内容中。我们知道地址是不存入内存的,那么我们怎么把左边一列的地址也存入到内存中呢?
这时候指针就出现了
指针的定义
如下图所示(刚刚上面的图),每一个字节都有一个对应的编号,因为我们上面定义的是int a值为5,所以占4个字节,第一个字节05(代表值转换为二进制就是 0000 0101 也等于10进制的5)以及后面的 00 00 00都是属于int a的。
比如:05这个字节对应的是0x006FF934 下一个字节00对应的是0x006FF935 再后一个字节00对应的是0x006FF9306,以此类推。
为什么是一个字节一个编号呢?
因为CPU访问最小的单位就是字节不而是位,所以才会一个字节一个编号。
我们之前说过指针变量的变量名就是用来存地址的,例如下面程序:
#include<stdio.h>
int main() {
int i = 123;
int* i_pointer = &i;//&表示取地址
}
过程如下图:
比如i的地址值是2000,那么i_pointer的内存里的值就是2000
下面我们用我们程序debug中的内存佐证一下
可以看到,i_pointe内存存的就是i的地址00EFFBE4,因为AMD规定存储是低位到高位所以就是e4 fb ef 00。
注意:
i是int类型的,所对应指向它的指针也应该是int类型的
&表示取地址
取地址操作符与取值操作符
&是取地址,✳是取值
(只有指针变量才能用✳)
前面我们提到过直接访问与间接访问,下面我们就来演示一下
#include<stdio.h>
int main() {
int i = 123;
int* i_pointer = &i;//&表示取地址
printf("%d\n", i);//直接访问
printf("%d\n", *i_pointer);//间接访问
return 0;
}
可以看到,他们的输出结果都是123。但是访问方式确是不一样的
第一个输出语句属于直接访问,直接找到i的地址输出其内容。
第二个属于间接访问,系统先找到i_pointer的地址,再根据i_pointer内存里的地址找到i(因为i_pointer里存的就是i的地址),然后再输出i的值。
过程可以如图所示
&就是获取地址,✳就是取出对应地址的值。可以理解为&就是宝藏的地址,✳就是根据宝藏地址找出来的宝藏
注意:定义多个指针变量时
int* a, * b, * c;
不要
int* a, b, c;
这样定义只有a时指针类型
可以看到这样定义b和c都是int类型不是指针类型。