c语言学习笔记

本文介绍了C语言的基础知识,包括变量的定义与赋值,常量的使用,输入输出函数如scanf和printf的运用,以及如何进行字符串操作。文章还详细讲解了不同类型的循环结构如while、for和do-while,以及如何使用break和continue控制循环。此外,函数的定义、调用与参数传递也被提及,特别是涉及指针时如何交换变量值和作为函数返回值的情况。最后,文章讨论了数组的使用,包括一维和二维数组,以及字符串在C语言中的处理方式。

第一个程序

输出: printf("") ""里是字符串,\n是换行

每一行代码都要有分号 隔几个格没有关系 再下一行没有别的语句就可以

做计算


#include<stdio.h>

int main()
{
    printf("%d",12+34);
    
    return 0;
}

这里的%d用法和python一样 都是把后面要输出的内容填到%d的位置上去

四则运算

基本数据类型

变量

算找零

变量定义

<类型名称><变量名称>;

int price

int prince,amount 是有两个变量,因为都是int所以放在一行里

标识符

变量的名字

规则:标识符只能由字母,数字,下划线组成;且数字不可以出现在第一个位置,关键字不可以用标识符

如何输入?

赋值和初始化

赋值int price=0

定义了一个变量,变量的名字是int,初始值是0;price=0是一个式子,'='是一个赋值运算,把右边的值交给左边

初始化 所有变量在第一次被使用之前应该被赋值一次;<类型名称><变量名称>=<初始值>

读整数

scanf("%d",&price);要求scanf读入下一个整数,读的结果赋值给变量price

找零代码


#include<stdio.h>

int main()
{
   int price=0;
   printf("请输入一个整数:");
   scanf("%d",&price);
   int change=100-price;
   printf("找您%d元\n",change);
    return 0;
}

变量输入


#include<stdio.h>

int main
{
    int a=0;
    int b=0;
    scanf("%d %d",&a,&b);
    printf("%d %d\n”,a,b);
    
    return0;
}

只要是出现在scanf("%d %d",&a,&b)格式字符串里的所有东西都是要读的,读完之后交给后面的某一个变量

但如果scanf("%d,%d",&a,&b)若输入1 2,结果却是1 0。是因为输入形式与代码形式不统一,应该输入1,2所以说对字符串的输入要求十分严格,假如不小心在第二个%d后面多摁了一个空格,那么在操作台上输入a,b的值后,还要输入一个才能够进行下去(但其实你输入的这个数不会对结果有影响,因为不会被读进去

所以出现在scanf字符串中的是要你去输入的,要不然就会出错

常量vs变量

再找零钱的代码中 int change=100-price,100是常数是不变的量

,而price和change是变量

直接写在程序中的量称之为直接量


#include<stdio.h>

int main()
{
   const int AMOUNT=100
   int price=0;
   printf("请输入一个整数:");
   scanf("%d",&price);
   int change=AMOUNT-price;
   printf("找您%d元\n",change);
    return 0;
}

const

是一个修饰符,放在int的前面,用来给这个变量加上一个不变的属性。这个const的属性表示这个变量的值一旦初始化,就不能再修改了

但是我们想让用户输入变量AMOUNT,而不是使用固定的初始值,把const删掉,改成变量


#include<stdio.h>

int main()
{
   int amount=100;
   int price=0;

   printf("请输入一个整数:");
   scanf("%d",&price);

    printf("请输入票面:");
    scanf("%d",&amount);
   int change=amount-price;

   printf("找您%d元\n",change);

    return 0;
}

plus.c(输入输出格式例子


#include<stdio.h>
int main()
{
    int a;
    int b;
    printf("请输入两个整数:");
    scanf("%d %d",&a,&b);#%d之间用空格隔开,输入的时候两个数也要用空格隔开
    printf("%d +%d =%d\n",a,b,a+b);
    return 0;
}

浮点数

计算身高的程序


#include<stdio.h>
int main()
{

    printf("请分别输入身高的英尺和英寸:");
    int foot;
    int inch;
    scanf("%f %f",&foot,&inch);
    
    printf("身高是%f米。\n",
   ((foot + inch /12.0)* 0.3048));#这里的12要改为12.0,因为前面是%f

    return 0;
}

在生活中呢,我们默认10和10.0是一个数,但是在计算机的角度来看并不是一个数,10.0是浮点数

double

double是双精度浮点数,后面的数字就不用改成浮点数的形式了


#include<stdio.h>
int main()
{

    printf("请分别输入身高的英尺和英寸:");
    double foot;
    double inch;
    scanf("%lf %lf",&foot,&inch);
    
    printf("身高是%lf米。\n",
   ((foot + inch /12)* 0.3048));#这里的12不用改为12.0,因为前面是double,但是是%lf

    return 0;
}

表达式

计算时间差

输入两个时间,每个时间分别输入小时和分钟的值,然后输出两个是时间之间的差,也以几小时几分表示


#include<stdio.h>
int main()
{
    int hour1,minute1;
    int hour2,minute2;

    scanf("%d %d",&hour1,&minute1);
    scanf("%d %d",&hour2,&minute2);

    int t1 = hour1*60+ mintue1;
    int t2 = hour2*60+ mintue2;

    int t =t2- t1;
    printf("时间差是%d小时%d分钟。",t/60,t%60)
    return 0;
}

运算符优先级

求平均数

注意赋值运算

a=b=6,运算顺序是自右向左,所以先算b=6,再算6=a

运算符

a = b + 5

a,b,5都是算子,+=是运算符

关系运算

  1. ==,!=,>=,<=,<,>

  1. 当两个值的关系符合关系运算符的预期时,关系运算的结果就为1,否则为0

  1. printf("%d\n",5==3)

因为5不等于3,所以不满足关系运算符的预期,运行结果为0

  1. 所有的关系运算符的优先级比算术运算符的低,但是比赋值运算的高

算数运算符>关系运算符>赋值运算符

  1. 判断是否相等的优先级比其他的低

  1. 连续的运算关系时从左到右进行

交换两个变量

int a=6; int b=5;

如何交换a,b的值

思路:假如有两杯子的水,你怎么交换呢,另取一个空杯子,那么变量交换也是如此,设设一个空值


#include<stdio.h>
int main()
{
    int a=5;
    int b=6;
    t=a;
    a=b;
    b=t;
    
    printf("a=%d,b=%d\n",a,b)
    return 0;
}

若想看到a,b,t三个值交换的过程

调试

先设一个断点 然后点击下一步

练习2-1


#include <stdio.h>
int main()
{
int cm=0;
scanf("%d",&cm);
int foot=cm/30.48;
int inch=((cm/30.48)-foot)*12;
printf("%d %d",foot,inch)

return 0;
}

题中给的是求厘米cm的式子,但输出要求是英尺和英寸,所以需要转换一下

选择结构

if语句做判断

if(成立条件){

}

else总是与最近的if匹配

找零计算器


#include<stdio.h>
int main()
{
int price;
int bill;
scanf("输入购买的金额:",&price);
scanf("输入支付的票面:",&bill);
if(bill>price)
    printf("%d",bill-price);
else
    printf("不需要找零钱")
return 0;
}

但是支付的钱不够购买怎么办


#include<stdio.h>
int main()
{
    int price=0;
    int bill=0;
    printf("输入购买的金额:");
    scanf_s("%d", &price);
    printf("输入支付的票面:");
    scanf_s("%d", &bill);
    if (bill >= price) {
        printf("应该找您:%d", bill - price);
    }
    else {
        printf("您的钱不够");
    }
    return 0;
} 

易错代码!


if(gameover=0)
    if(play2move=2)
        printf("you turn");
else
    printf("GAMEOVER")

最好不要这么写,因为计算机是else和最近的if匹配,但在这条代码中,else并不是与第二个if匹配

所以最优写法是


if(gameover=0){
    if(player2move=2)
        printf("you turn");
}
else
    printf("GAMEOVER");

这样就清晰的看到,else与第一个if匹配

所以要养成在if else后面加上{}的习惯

级联的if-else-if

exp1,2都是并列的

例子

x=0,x>0,x<0都是同阶级的,不存在谁包含谁

高质量代码

例题同上


int f;
if(x<0){
    f=-1;
}else if(x==0){
    f=0;
}else{
    f=2*x;
}
printf("%d",f);


int f;
if(X<0){
printf("%d",-1);
}else if(x==0){
printf("%d",0);
}else{
printf("%d",2*x);
}

if语句

1.

if(表示条件的逻辑表达式)

{

若干条件语句

}

若表示条件的逻辑表达式的结果不是零,那么执行{}中的语句

若结果为零,那么跳过这些语句不执行,而继续下面的其他语句

2.

若if语句这一行结束并没有;,且后面赋值语句写在if下一行且进行了缩进且有;

这时候就表明这条语句是if的一部分,且if语句也控制这条语句是否执行


if(total>amount)//total>amount这条语句控制了下一行语句是否会执行
    total+=amount+10;

两种情况的差别

情况一


#include<stdio.h>
int main()
{
int score;
int PASS=60;
printf("请输入成绩:");
scanf("%d",&score);
printf("你输入的成绩是%d.\n",score);
if(score<PASS)
    printf("很遗憾,这个成绩没有及格");
else
    print("祝贺你,这个成绩及格了");
printf("再见");

return 0;
}

情况二


#include<stdio.h>
int main()
{
int score;
int PASS=60;
printf("请输入你的成绩:");
scanf("%d",&score);
if(score<PASS)
    printf("很遗憾,这个成绩没及格");
else{
    printf("祝贺你,这个成绩及格了");
    printf("再见");
}
return 0;
}

switch-case

此代码的缺点就是,有可能输入的第一个值就是1,也可能输入的是4,如果是4的话,那么就需要将所有可能试过一边才能输出type==4时printf(再见)

更优解

case1,2,3,4,default是同时进行的


switch(控制表达式){
case 常量;
    语句
case 常量;
    语句
default;
    语句
}
  1. switch里的控制表达式只能是整数型结果

  1. 常量可以是常数,也可以是常熟计算的表达式

break

还是以上一个早上好的例子来说


scanf("%d",&type);

switch(type){
    case 1:
    case 2:
        printf("你好");
        break;
    case 3:
        printf("晚上好");
    case 4:
        printf("再见");
        break;
    default;
        printf("啊,有什么事");
        break;
}

当输入的是1时,但发现1没有语句,代码就会向下运行到case2,因为case2中有break语句,那么输出就是你好,就结束了

循环结构

用选择结构去做

小范围的数还可以这么做,但范围大的话是非常麻烦的

引入while语句

本人学过python表示爽歪歪

while的结构跟if一样

  1. {}里是循环体

  1. 循环体要有改变条件的机会(如过没有跳出循环的条件,就会变成死循环)

验证

do-while循环

while和do-while的区别:

do-while是无论条件满不满足都先至少执行一遍

while是只有条件满足时才执行循环


int x;
scanf("%d",&x);
int n =0;
do
{
    x/=10;
    n++;
}while (x>0);
printf("%d",n);

猜数游戏

描述思路

但是给的随机数很大

所以随机数就控制在100以内,方便用户去猜

显然这里就要用do-while循环,不管怎么样,总要先让用户先猜一个数,所以先要进行一次循环,这是while循环所不能做到的

完整代码

算平均数

算法

两种循环都可以做,但是很显然while只进行一次就可以,但do-while循环需要做两次,针对这个题,不需要去不看任何条件不管三七二十一就执行一次

整数的分解


int main()
{
    int x;
    x=12345;
    int digit;
    int ret=0;
    while(x>0){
        digit=x%10;//取单个位数上的数
        ret=ret*10+digit//将x倒过来
        printf("x=%d,digit=%d,ret=%d",x,digit,ret);
        x/=10;
}
    printf("%d",ret);
    return 0;
}

for循环

例子:阶乘

用while循环来做


int n;
scanf("%d",&n);
int fact=1;
int i=1;
while(i<=n){
    fact *=i;
    i++;
}
printf("%d!=%d\n",n,fact);

用for循环


int n;
scanf("%d",&n);
int fact=1;
int i=1;
for (i=1;i<=n;i++){//i=1是初始条件,i<=n是循环继续的条件,i++是循环每一轮要做的
    fact*=i;
}
printf("%d!=%d\n",n,fact);

循环控制变量i只在循环里被使用了,循环外面它没有任何用处。因此,我们可以把变量i的定义写到for语句里面

但是出现了错误,只有c99才能用

循环次数

三种循环的使用区别

break语句(判断素数

但是进行断点测试时发现,即使发现x%i==0,能够整明x是素数了,但无法停止,程序还会往下进行i++,这时就需要break出手啦

有了break,只要有一次x%i==0,就会停止

continue跳过循环

将上面的例题做些变动,加入一个要求:输出每一次循环时,正测试的i的值

9是素数,所以循环的时候会出现两种情况

  1. i=2,这类9无法整除的数,不满足9%2==0,所以没办法进入if循环,就会执行printf("%d\n",i)这条语句,然后因为,没有break停止循环的语句,就会进入下一次循环

  1. i=3,这类9能够整除,能够证明9是素数的数,满足9%3==0的条件,能够进入if语句且执行到continue会停止循环,跳到循环外的printf("%d\n",i)

循环的嵌套

  1. 求100以内的素数

  1. 求50个素数

50个素数的范围就不确定了,这时应用到while循环

其实就是把上一个的外循环换成while循环,但不要忘记循环进行的条件x++

而且需要加一个计数器,因为要前50个素数,循环一次如果发现是素数就+1

还有一种思路就是,依照计数器的次数进行循环

  1. 凑硬币

但是输出的结果有太多了

那就在程序结束的时候加一个break将执行暂停

函数

引入

1.求素数的和

在for循环内有几行判断素数的代码,与循环外的代码又没有关系,这个时候就可以把它单独拎出来

也就是自己定义一个判断素数的函数

这样一来主函数就变得简便很多,同时也可以反复利用这个函数,在主函数内的任何地方都可以用

2.求和

求出1到10,20到30和35到45的三个和

在这道题中,有三段一模一样的代码,这时可以调用函数来减小运算

函数的定义

函数名(参数值);

  1. ()起到了表示函数调用的重要作用

  1. 调用的的话时候即使没有参数也需要()

  1. 如果没有打上(),会提示warning

意思是表达式的结果没有被使用

  1. 参数会被按照顺序依次用来初始化函数中

在这张图里被用的就是35,45

例1


void cheer()
{
    printf("cheer\n");
}

int main()
{
    cheer();
    return 0;
}

输出结果为cheer

知识点3:


void cheer()
{
    printf("cheer\n");
}

int main()
{
    cheer;//没有()
    return 0;
}

结果会warning,但函数并没有被调用

回到引入2

函数的返回值

return

一旦遇到return函数就停止,如果return后有值,就送回去一个值

例2 比大小

进行调试取研究return

断点设在第一个引用函数的地方

就进入定义的函数max

max(10,12)所以,a=10,b=12

执行到return,ret为12

继续向下进行

这时的c值为12,因为第一次调用函数结果return为12

继续的话,就是主函数里初始化的a,b的值带入定义函数中

return返回的值为6

那么此时c=6

再继续进行,第三次调用函数返回的值为23

此时c=23

多出口不好

有两个return出口,当需要修改时不方便

没有返回值的函数

  1. void函数名(参数表)

  1. 不能使用带值的return

  1. 可以没有return

  1. 调用的时候不能做返回值的赋值

函数原型

函数先后关系

编译器会自上而下分析代码,所以调用函数之前先定义好

函数原型

参数传递

  1. 如果函数有参数,调用函数时必须传递给它数量,类型正确的值

  1. 可以传递给函数的值是表达式的结果包括:字面量

变量

函数的返回值

计算的结果

参数的值的类型不匹配

如果函数的参数值的类型是int,但你输入的不是int

例:类型是int,输入了2.4

输出结果会为2,但不会出现错误

传过去的是什么

运行之后发现,主函数的a,b的值并没有互换,虽然定义函数中有a,b,但不是一回事,主函数中的

a的值给了swap里的a,主函数中的b给了swap里的b

所以实际上主函数的a,b的值并没有改变

本地变量

  1. 函数的每一次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量

  1. 定义在函数内部的变量就是本地变量

  1. 参数也是本地变量

变量的生存期和作用域

断点调试来进一步阐释生存期和作用域

当断点在y=t时,swap(a,b)里的a,b存在,但作用域不在当前

当执行到swap(a,b)时,离开main的变量空间,跳到定义的swap函数空间内,也就是说即使两个空间内的变量的名称一样,但是没有任何的关系,在swap函数的变量空间内对变量a,b,t做怎样的改变,main函数变量空间内的变量都不发生改变

规则

第二条:

程序运行进入这个块之前,其中的变量不存在,离开这个快,其中的变量就消失了

第三条:在块外定义的变量在块内仍然有效

第四条:在块内定义了与块外同名的变量,则掩盖块外的变量

其他细节

声明时不加参数

如这段代码,声明的时候没有明确告诉参数的类型,但在主函数调用swap函数时,值给的类型时int,但定义swap函数时,参数类型为double

输出:

逗号运算符

C语言不允许函数嵌套定义

int i,j,sum(int a, int b)

定义变量i和j,声明要int a,b作为sum函数的参数,且返回值为int

return(i) ; =return i ;

二者一个意思,前面看起来像错的

数组

引入

int num[100]是可以放100个int型整数的数组

草泥马肯定会忘 到时候再看一遍

基本内容

定义数组

如果变量名称后面没有元素的数量,那么它就是一个变量

什么是数组

例3

数组的单元

有效的下标范围

数组a是从0到9,不存在a[10],所以越界出错

但是会看引用的例子,用户很可能输入多于100的数字,但定义数组的时候定义的是100,就会发生了越界都错误,所以要进行调整

就是先让用户输入要输入数字的数量,要输入多少个,直接用用户输入的个数值作为数组的元素数量值,这样就避免了越界的现象

数组创建之后不可以改变

长度为0的数组 int a[0],存在但没用

例4

数组的运算

  1. 数组的集成初始化

int a[]={2,4,6,7,1,3,5,9,11,13,23,14,32}
  1. 直接用大括号给出数组的所有元素

  1. 不需要给出数组的大小,编译器替你数了

测试

测试结果为

变形

测试结果

输出就是:2 0 3 6 0 0 0 0 0 0 0

初始化:

之前的初始化:

定义数组时,直接初始化:

  1. 数组的大小

用sizeof

  1. 数组的赋值

search例题!

二维数组

二维数组的遍历

二维数组的初始化

例题:井字游戏

指针

取地址运算

运算符&

获得变量的地址,操作数必须是变量

可以用%p求得字符i地址的大小

或者是

指针

当被调用的时候得到了某个变量的地址

void f(int*p);

当调用的时候也要填f(&i);

指针的意义

i的值为6,地址为70,定义的f函数的变量p是存放变量i的地址的,使得f函数拥有访问变量地址的能力,指针p的定义就是:int*p=&i

改变变量地址

*是访问变量地址的单目运算符

*p可以做左值,也就是可以去写它的值

也可以做右值,也就是访问它的值


void f(int *p);
void g(int k);

int main()
{
    int i=6;
    printf("&i=%p\n",&i)//访问变量i的地址
    f(&i);//因为f函数是访问地址的函数,所以调用函数时填的值要加上取地址符&
    g(i);
    return 0;
}

void f(int *p)
{
    printf("p=%p\n",p);
    printf("*p=%d\n",*p);
    *p=26;//这时改变了i的地址
}

void g(int k)
{
    printf("k=%d\n",k);
}

输出结果:

发现i的值已被改变

f,g两个函数的本质就是值的传递

左右值
  1. 这里的a就是左值,用于标识特定数据对象(用于存储值的数据区域)的名称或表达式

b就是右值,是能复制给可修改左值的量

  1. 左值指定一个对象可以引用内存中的地址

右值可以用表达式的值这一概念来描述

  1. 等号不是区分左右值的标准,但是赋值运算符=左侧运算对象,应该是可修改的左值

间接运算符*

获取指针地址上对应的


int*p=&a;//指针变量p存储的是a的地址
int d=*p;//通过获得的a的地址,找到其对应的值,赋值给变量d
*,&

假定有一个变量名为a的变量空间,将变量a初始化为2

*p是取某地址的值,也就是说变量p存储的数据是a的地址,*p表达的是地址上的值2

&a是取值所在的物理位置(也就是地址)

int*即是指针,int*p=&a,这条语句表达的就是,让新变量p存储a的地址

指针的应用场景

一.交换两个值的变量
二.函数返回多个值

由于函数的返回值return只能返回一个,所以选择用指针来解决这个问题

三.函数返回运算的状态,结果用指针返回
常见错误

定义了指针变量,但是没有让它指向任何变量,就开始使用了

指针与数组

将一个普通变量传入函数,得到的是一个值,若将一个指针放入函数,得到的也是一个值,那将数组放入函数会得到什么呢

求同一个变量在不同函数中的大小

函数名 sizeof(变量)

得到的是指针

所以列表在函数里就相当于指针,也就是说sizeof(a)==sizeof(int *)

数组变量是特殊的指针

原理:有一个变量min,变量内的值是2,有一个指针p,p内的值是变量min的地址,所以p指向2,

  1. 数组不需要取地址符&,但是数组的单元表达的是变量需要用到&,a==&a[0]

  1. p[0]是将一个已赋值的变量当作一个数组,那么这个数组的长度就是1,变量被赋予的值也就是数组[0],所以[]可以对指针做,也可以对数组做

  1. 运算符既可以对指针做,也可以对数组做,且数组的地址是首元素的地址

  1. 数组变量是const指针,不能被赋值


int a[]=b;//是不可以的
int a[]-->int*const a//const是代表常数,也就是说数组a不能被改变

指针与const

指针是const

一旦得到了某个变量的地址,不能再指向其他变量

int*const q=&i;这条代码的意思就是,q只能指向i,不可以指向别人

*q=26;这条可以执行,因为*q所指向的i不是const,可以改变

q++;不可以,q是const类型,不可以改变

所指是const

const int* q=&i;

i的值可以改变,p可以改变指向,但是不能通过*p改变i的值

两种类型

转换

把非const转成const


void f(const int*x);
int a=15;
f(&a);
const int b=a;

f(&b);
b=a+1;//不可执行

用于当要传递的参数的类型比地址大的时候

优点:既能用较少的字节传递值给参数,又能避免函数对外面的变量的修改

const数组

const int a[]={1 2 3 4 5 6};这条语句是将a数组的所有元素固定住了

所以这种数组必须痛过这种方法初始化赋值,否则写出来没办法赋值

指针运算


char ac[]={0,1,2,3,4,5,6,7,8,9};
char *p=ac;
pritnf("p=%p",p);
printf("p+1=%p",p);
/*输出的p和p+1 只相差1
改用int类型看看*/
int ac[]={0,1,2,3,4,5,6,7,8,9};
int *p=ac;
pritnf("p=%p",p);
printf("p+1=%p",p);
//输出的q和q+1相差4,同时注意是十六进制

*(p+1)

若*p=a[0]

*(p+1)=a[1]

意义

前提是指针指向的是连续的空间,否则没有意义

指针的算术运算

  1. 给指针加减一个整数

  1. 递增递减运算(++/--)

  1. 两个指针相减


char ac[]={0,1,2,3,4,5,6,7,8,9};
char *p=ac;
char *p1=&a[5];
pritnf("p=%p",p);
printf("p+1=%p",p);
printf("*p-p=%d",*p-p)
//输出为p1-p=5

*p++

由于++是后缀,所以先使用p,再加1(取地址动作与p加1动作同步)

通常用于遍历


char ac[]={0,1,2,3,4,5,6,7,8,9};
char *p=ac;
for(i=0;i<sizeof(ac)/sizeof(ac[0]);i++){
    printf("%d\n",ac[i]);
}//遍历法一
for(p=ac;*p!=-1;p=++){//p=ac,是指针P指向数组ac的头
    printf("%d\n",*p);
}//遍历法二
while(*p!=-1){
    printf("%d\n",*p++);
}

*p++的意义是:取出p所指的数据,完事之后顺便把p移到下一个位置去

指针比较

指针的比较,地址大小的比较

0地址

指针的类型

指针的类型转换

void*表示不知道指向什么东西的指针

int*p=&i;

void*q=(void*p);

并没有改变p所指的变量类型,i还是int

补充

指针变量类型

意义:不管是什么类型的指针变量,所存的值都是地址(int类型的值)。那么声明不同类型的作用是什么?答案是规定指针在内存中每次移动的字节数。

例如定义“int *pa = &a”,取值时,int类型占4个字节,指针就从首地址开始移动,读取4个字节。同理,short类型占2字节,指针就移动2字节。通过声明指针类型,告诉指针每次移动多少字节,来获取变量的值。

字符串

字符数组

这样并不是c语言的字符串

若在最后加上一个\0就是了

字符串

  1. 以0结尾的一串字符

0或\0是一样的,但是和'0'不同

  1. 0标志字符串的结束,但并不是字符串的一部分

计算字符串长度的时候不包括这个0

  1. 字符串以数组的形式存在,以数组或指针的形式访问

更多是以指针的形式

  1. string.h里有很多处理字符串的函数

字符串变量


char*str="Hello";//str 指针指向一个数组,它的内容是Hello
char word[]="Hello";//有一个数组word,它的内容是Hello
char line[10]="Hello";//有一个数组大小为10,往数组里放了Hello,Hello是5个字符,但占据多大的空间呢

回答第三行代码的问题,由于是c语言的字符串,所以Hello占数组word是六个字节

字符串常量

“Hello”

  1. 由双引号括起来的叫字符串常量

  1. “Hello”会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0

  1. 两个相邻的字符串常量会被自动连接起来

那如何解决这个问题呢

"内容A""内容B"——>输出就是内容A内容B

"内容A\内容B"——>输出就是内容A 内容B

那接下来做点什么吧


char*s="Hello World";
s[0]='B'
printf("Here!s[0]=%c\n",s[0]);
//此段代码不可行,为什么呢?
char*s="Hello World";
char*s2="Hello World";
printf("s =%p\n",s);
printf("s2=%p\n",s2);
//输出发现,s,s2,被赋予了相同的值,也就是他们所指的位置一致都是0xe1f82
int i=0;//称i为本地变量
printf("&i=%p",&i);
//输出为0xbff1fd6c,一对比发现,i在很大的地方,而s在很小的地方

看图可知,字符串"Hello World"在很小的地方,被称为代码段

如果试图改写这段字符串,那么程序会崩溃掉

但如果非要改呢

char s[]="Hello World"

两者区别就是,前者是指针指向了"Hello World",后者是将"Hello World"放在自己那里

?写成指针的形式还是数组的形式

总结就是:构造字符串用——数组

处理字符串——指针

char*是字符串?
  1. 字符串可以表达为char*的形式

  1. char*不一定是字符,char*表达的是,这有一个指针指向一串字节

  1. 只有它所指的字符串数组结尾有0,才能说所指的是字符串

字符串输入输出

字符串的赋值

char *t="title";
char *s;
s=t;

图解:

输入输出

输出为

  1. 不能用运算符对字符串做运算

  1. 通过数组的方式可以遍历字符串

  1. 字符串字面量可以用初始化字符数组

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值