沈杰同学大概是beyond的铁粉,已经连续两次早会上放他们的歌。不过不可否认,家驹同学的歌确实都还蛮励志的。沈杰同学每次开早会都颇有教授范儿,说话一板一眼,很有趣,私底下确是个活跃分子。每个集体中其实都需要这样一个人。
生兔子的题目简化版:
#include<stdio.h>
int i = 1,j = 1,k = 0,m = 2;
void main()
{
while(m < 30)
{
k = i + j;
i = j;
j = k;
m++;
}
printf("\n%d",k);
getchar();
}
一题了解for循环:
#include<stdio.h>
int i = 1,sum = 0;
void main()
{
for(i = 0;i != 10;i++)
{
sum += i;
}
printf("%d\t%d",i,sum); //10 45
getchar();
}
一,字符数组
在 C 语言中,字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。
由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个。(注意空格也算一个字符 )
char greeting[6] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’};
依据数组初始化规则,可以把上面的语句写成以下语句:
char greeting[] = “Hello”;
char s1[5] = {1,2,3,4,5};
printf("%s",s1);
getchar();
这样就会有乱码,因为该字符数组没有结束符\0,或者说没有预留\0的内存空间。
定义时安全动作:初始化字符数组char s1[30]=”\0”;
字符串的截取:
截取“He”:
# include<stdio.h>
char ch1[6] = {'H','e','l','l','o'};
void main()
{
char *p;
p = ch1;
*(p + 2) = 0;
//这一步是将结尾设置成空字符,ascii码0对应的是null,即“\0”,必须有这一步。否则会打印直到遇到空字符为止。
printf("%s",p);
//这里是p,如果写*p则是打印字符'H',前面必须改成%c,就像这样:printf("%c",*p);
getchar();
}
在C语言中,字符串是以\0结尾的字符数组。因此printf库函数在计算字符串长度的时候都是找到\0才结束,按%s输出字符数组的时候也是到\0结束,所以有时候如果没有给字符串加\0结束符,会看到乱码,就是这个原因。
‘\n’代表ASCII码为0的字符,从ASCII码表中可以查到ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不干。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。
????
为什么打印字符数组的首地址,可以输出字符串
在c语言中,将字符串作为字符数组来处理。(c++中不是)
????:
int a[5] = {1,2,3,4,5};
int *p = {1,2,3,4,5} // 报错,不允许
char str[ ]=”I love China”;
char* str=”I love China”; //允许
C语言对字符串常量是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串常量,程序在定义字符串指针变量str时只是把字符串首地址(即存放字符串的字符数组的首地址)赋给str。
定义字符串有两种方法:
一、字符串指针 char *string=”abcde”;
二、一维字符数组。例如:char string[10];
字符数组的赋值
对字符数组只能对各个元素赋值,不能用以下方法对字符数组赋值
char str[14];
str=”I love China”; (但在字符数组初始化时可以,即char str[14]=”I love China”;)
而对字符指针变量,采用下面方法赋值:
char* a;
a=”I love China”;
或者是 char* a=”I love China”; 都可以
字符数组的整体赋值只能在字符数组初始化时使用,不能用于字符数组的赋值,字符数组的赋值只能对其元素一一赋值,下面的赋值方法是错误的
char str[ ];
str=”I am happy”;
因为如果定义了一个字符数组,那么它有确定的内存地址;而定义一个字符指针变量时,它并未指向某个确定的字符数据,并且可以多次赋值。
处理字符串输入输出的函数:
scanf () , printf(),puts(), gets()
,
#include<stdio.h>
char ch[100];
void main()
{
scanf("%s",ch); //输入“hello”
getchar();
printf("\n%s",ch); //输出“hello”
getchar();
}
**下列函数需引用头的文件:<string.h>
复制 strcpy(s1, s2);
复制字符串 s2 到字符串 s1。
只对第一个字符长度的限制,对第二个字符串没有长度限制。
s1和s2所指内存区域不可以重叠且s1必须有足够的空间来容纳s的字符串。
拼接 strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾,返回的是s1.
测量 strlen(s1);
返回字符串 s1 的长度。strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止,然后返回计数器值(长度不包含’\0’)
比较 strcmp(s1, s2);
当s1
字符串中寻字符首现地址 strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
字符串中寻字符串首现地址 strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
题目:小写转大写
#include<stdio.h>
void main()
{
int i = 0;
char s1[30]="\0";
char *p = s1;
printf("请用小写字母输入一个字符串:\n");
scanf("%s",s1);
getchar();
printf("大写转换:\n");
while(!(*p == '\0')) //注意这里的写法
{
printf("%c",*p - 32);
p++;
}
getchar();
}
C语言 gets()和scanf()函数的区别:
scanf 不能接受空格、制表符Tab、回车等;只要遇到他们即认为输入结束。并且会自动在字符串后面添加’\0’,但是回车,空格和tab键仍会留在输入的缓冲区中
gets 能够接受空格、制表符Tab等; 所以允许间隔输入,只有遇到回车才认为输入结束。会接受回车键之前输入的所有字符,并用’\n’替代 ‘\0’.回车键不会留在输入缓冲区中。和它配合使用的puts函数,在输出字符串的时候自动换行。
gets()用到读取字符串
scanf()可以读取所有类型的变量
指针
1,指针指向的是地址,地址指向的是值。
2,指针变量就是将另一个变量的地址作为值保存在自己的地址上。比如*p = &a,这时我们称p是指向a的指针。
3,指针有改变它所指向的变量的值的功能。你的值在你的地址里,而你的地址在我的地址里,可以理解为指针获取了操控其所指向的变量的权限。通俗一点,你在你的房间里,而你的房间在我的家里,我是你的主人,当然有访问你,干涉你的权限。
4,指针作为形参时,传入的是变量的地址,在被调函数中可以通过该地址取得变量的原始值并重新赋值,此时原函数中的变量也会随之修改。这是指针功能的具体体现。
5,int *p = &a,可以分解为两步,int *p; p = &a
定义时的“*”只是代表后面的变量是一个指针变量他是一个标志,
完成定义以后‘*’ +指针变量才是取值。
6,指针变量定义以后需要初始化,即给其赋值一个确定的地址,否则就是野指针,参与指针运算以后可能会出现不可预见的错误,有系统崩溃的风险。
指向指针的指针,指针与数组
**重点内容**1,指针的指针,其实就是二级指针。参考指针的概念,很容易理解。就是一个新的指针变量,它的地址里保存着另一个指针变量的地址。还是那个通俗的比喻:a住宅&a里,&a住宅&b里,&b住在&c里。所以c可以直接操作b,b又可以直接操作a,所以c可以间接操作a.例如:
int a = 10,b = 11,*p1,**p2 ; //注意这里的变量名分别是p1,p1
p1 = &a; p2 = &p1; //p1整形变量a的指针,p2是指针变量p1的指针
*p1 = 20; //指针变量P1通过a的地址获取a的值并重新赋值为20
*p2 = &b; //通过二级指针p2改变一级指针p1的指向,从指向a变为指向b
*p1 = 30;(或者**p2 = 30) //转向后的指针p1通过b的地址获取b的值并重新赋值为30
printf("%d\t%d",a,b); //此时打印的结果a = 20,b = 30
2,指针与数组这一节又分:指针与一维数组&指针与二维数组,这里涉及到指针运算
指针的运算主要包括:+,-,++,–。其实就是所指地址的移动。
两个公式:一维数组:*(p+i) = a[i] (下标逐个移动)
二维数组:((p+i)+j) = a[i][j] (i为行移动,j为列移动)
3,所有指针默认指向的都是目标变量首字节的地址,这句话可以判断能否精确取值的问题。比如:
int a[2][3] = [{1,2,3},{4,5,6}]
a指向整个数组,并默认指向第一行,*a无法取到1。
a[0]指向数组第一行,并默认指向第一行第一个元素,所以*a[0]可以取到1。
&a[0][0]无需默认,它精确的指向第一行第一个元素,所以*(&a[0][0])可以取到1.
4,指向数组的指针叫数组指针。
一维数组指针:
int *p = a; (或&a[0]都可以)
数组指针也可以有下标,比如p[5],代表当前所指的下标往后移5个。
二维数组指针:
int(*p)[4]; (表示其指向的是一个列数为4的二维数组指针)
此定义模式下的p才有行移动的功能。其它模式下如int *p = a[0]/&a[0]/&a[0][0]都只能逐个移动
数组传参的特殊性,数组指针,函数指针。
1,数组作为实参传入数组时,为了节约,形参并不重新分配内存。此时如果函数内用指针操作的其实是数组原始地址上的值,所以能够实现形参实参的双向互动。
2,数组指针,周二部分已讲。
3,函数指针,函数指针指向函数以后,通过指针就可以调用函数,主要是格式:
定义 int (*p)(int a,int b) 相当于去掉函数体,替换函数名,第一个小括号不可省略。
赋值 int = add add是函数名,跟数组一样,函数的函数名指向整个函数的地址
调用 p(a,b)
字符数组,字符串,处理字符串的函数:
由于博客今日内容部分已详细描述,周小结部分就不做细致描述,罗列几个重点:
1,字符数组和字符串在内存中的存储格式是一样的,可以认为字符串就是字符数组。
2,字符数组的长度比字符个数要多一个,因为要预留一个位置给空字符\0,因为它是字符串结尾的标志,也是必不可少的部分。
3,printf(“%s”,p),是可以得到完成字符串的。
4,字符串可以这样定义,char *ch1 = “hello china”,但是 int *p = {1,2,3,4}不可以。
5,要打印单个字符需要这样printf(“%c”,*p)
6,处理字符串的函数,应用的头文件是string,h