3/4/24运算符、关系逻辑表达式、循环体语句、一维数组、指针

目录

运算符分类

关系表达式与逻辑表达式

 OJ练习

平闰年

整型,字符型,浮点型三个变量的求和值 

if-else

while循环

for循环

continue语句

break语句

OJ练习

  回文数判断

n的阶乘

换零钱

一维数组

数组的访问越界

数组的传递

字符数组

gets函数与puts函数

str系列字符串操作函数

 OJ练习

统计数字出现的个数

 比较字符串

指针

指针的定义

 取地址操作符欲取值操作符

指针的传递

指针的偏移

指针与动态内存申请


对于for循环各部分的作用理解更加深刻。

字符数组与字符串的区别在于末尾是否有"\0"。

指针的本质是地址,指针传递的本质是函数调用是值传递。

高效的栈空间中会消除结束调用的栈空间,而malloc申请的堆空间只能被free释放。

运算符分类

C语言提供了13种类型的运算符

  1. 算术运算符(+ - * / %)
    1. 乘、除、取余的优先级高于加、减
    2. %为取模运算符,返回值是余数而不是商
  2. 关系运算符(> < == >= <= !=)
    1. 返回值只有真和假,对应1和0
    2. 关系运算符优先级低于算术运算符
    3. while(scanf("%d), &a),其中sancf返回成功匹配读取的个数,当输入不匹配时返回0,while跳出循环。(3<a<10)表示((3<a)<10)始终为true,不表示判断a是否在(3,10)区间的数,应该配合逻辑运算符使用(3<a &&a <10)
  3. 逻辑运算符(! && ||)
    1. 逻辑非的优先级高于算术运算符,逻辑与和逻辑或的优先级低于关系运算符。
    2. 逻辑非从右至左运算。eg:int j=6;int i=!!j;。i结果为1。
    3. 逻辑与和逻辑或的短路运算。逻辑与有假则假,先假短路;逻辑或有真则真,先真短路。
  4. 位运算符(<< >> ~ | ^ &)
  5. 赋值运算符(=及其扩展赋值运算符)
    1. 只有确定值的变量才能成为左值。
  6. 条件运算符(?:)
  7. 逗号运算符(,)
  8. 指针运算符()* &
  9. 求字节运算符(sizeof)
    1. 不是函数,得到常量或变量所占用的空间大小。
  10. 强制类型转换运算符((类型))
  11. 分量运算符(. ->)    —结构体
  12. 下标运算符([])    —数组
  13. 其它(如函数调用运算符())    —函数

关系表达式与逻辑表达式

双目运算符:需要左操作数和右操作数。

单目运算符:只需要一个操作数。

算术运算符>关系运算符>逻辑与或

相同优先级的运算符从左至右进行结合

eg:5>3&&8<4-!0。注意逻辑与是否存在短路,因此应该先计算5>3而不是!0,最终1&&0结果为0。

 OJ练习

平闰年

能被4整除但不能被100整除,或者能被400整除

#include <stdio.h>

int main()
{
  int year;
  scanf("%d", &year);
  (year%4==0 && year%100!=0||year%400==0)?printf("yes"):printf("no");
  return 0;
}

整型,字符型,浮点型三个变量的求和值 

考察scanf读取多种类型;混合类型运算,输出格式的控制;混合输入时%c前需要加入一个空格

#include <stdio.h>

int main()
{
  int i;
  char j;
  float k;
  scanf("%d %c %f", &i, &j, &k);
  printf("%.2f", (float)i+j+k);
  return 0;
}

if-else

单句也注意加上花括号,养成良好习惯的同时防止修改后出错。

while循环

“当型”循环,表达式的值非0时,执行while中的内嵌语句。先判断表达式后执行语句,注意跳出循环的条件从而避免死循环。while后面不能加分号,否则也会进入死循环。

for循环

可用于循环次数不确定而只给出循环结束条件的情况,让完全可以代替while。一般形式为for(表达式1;表达式2;表达式3) {语句};

  1. 先求解表达式1。
  2. 再求解表达式2,若其值为真(非0),则先执行for语句中对应的内嵌语句。
  3. 求解表达式3,再转会第2步继续判断执行。
  4. 循环结束,跳出for循环,并执行后面的程序。

值得注意的是:

  1. 循环语句中必须有且只能有两个分号,用于分割表达式1、表达式2、表达式3。
  2. 表达式1、表达式2、表达式3都可省略。
  3. 3个表达式的作用:
    1. 表达式1:
      1. 设置初始条件,只执行一次。
      2. 可以为零个、一个或多喝变量设置初值。
    2. 表达式2:
      1. 循环条件的表达式,用于判断是否继续循环。
      2. 在每次循环体前先执行此表达式,决定是否继续执行循环。
    3. 表达式3:
      1. 循环的调整,用于使得表达式2的结果不断趋近非真从而跳出循环。
      2. 同样可以设置为任意数量个变量的调整。 
  4. 表达式1和表达式3的值都可以在结构体中进行调整。

continue语句

结束本次循环,即跳过循环体中下面尚未执行的语句,在for循环中会接着进行是否执行下次循环的判断,在while中要具体分析。

break语句

结束整个循环过程,在for循环中不再判断执行循环的条件是否成立。

OJ练习

  回文数判断

输入一个整型数,判断是否是对称数,如果是,输出yes,否则输出no,不用考虑这个整型数过大,int类型存不下,不用考虑负值;

 一般使用while循环,利用中间变量存储首位和末位,设置跳出while循环条件。彻底理解for循环的机制后减少了中间变量的使用,有效利用3个表达式的作用。

#include <stdio.h>

int main() {
    int a;
    scanf("%d", &a);
    for (; a > 10; a = a / 10 % 10) {
        if (a / 10 != a % 10) {
            printf("no");
            break;
        }
        if (a < 10) printf("yes");
    }
    return 0;
}

n的阶乘

利用while或者for循环计算n!的值。1≤n≤10。

#include <stdio.h>

int main() {
    int total = 1, n;
    scanf("%d", &n);
    for (1; n > 0; n--) total *= n;
    printf("%d", total);
    return 0;
}

换零钱

某人想将手中的一张面值100元的人民币换成10元、5元、2元和1元面值的票子。要求换正好40张,且每种票子至少一张。问:有几种换法?

int main() {
    int n = 0;
    for (int i = 1; i <= 83; i++) {
        for (int j = 1; j <= 42; j++) {
            for (int k = 1; k <= 15; k++) {
                for (int z = 1; z <= 9; z++) {
                    if ((i + j + k + z == 40) && (i + j * 2 + k * 5 + z * 10 == 100)) n++;
                }
            }
        }
    }
    printf("%d", n);
    return 0;
}

一维数组

一组具有相同数据类型的数据的有序集合。

声明数组要遵循以下规则:

  1. 数据名的命名规则和变量名相同,即遵循标识符命名规则。
  2. 定义数组时,需要指定数组中元素的个数,即数组长度。
  3. 元素个数要使用常量表达式,不能使用变量表达式。C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
  4. 定义时,可以只对一部分元素使用花括号对应初始化,剩余未赋值的元素默认为0。
  5. 使一个数组中的全部元素值为0,可写作int a[10]=0;
  6. 可以不指定数组长度直接赋值,但不推荐使用,元素个数不直观。int a[]={1, 2, 3};

数组的访问越界

编辑器并不检查程序对数组下标的引用是否存在数组的合法范围内,访问越界会导致错误的使用到对应地址的其它常量。

数组的传递

数组传递到子函数不能通过sizeof得到长度,子函数得到的是数组的指针,即数组的起始地址。通过指针是可以修改数组元素值的。

字符数组

以'\0'(值为0)为结束符。

scanf读取字符串操作时,匹配到空白符(空格、tab或回车)会自动往字符数组中添加结束符。

联系scanf的用法,%s自动忽略空白符。 

gets函数与puts函数

gets函数类似于scanf函数,用于读取标准输入。scanf函数在读取字符串时遇到空白符会自动结束读取,因此当输入的字符串中存在空格时,需要使用gets函数进行读取。

注意:在字符串中'\0'不会被统计进字符串的长度中,而字符数组会统计'\0'进字符数组的长度中。

gets函数格式:char *gets(char *str);

gets函数一次读取一行,直到匹配到换行符自动结束并在字符串数组中添加\0,换行符遗留在缓冲区。

puts函数类似于printf函数,用于输出标准输出。

puts函数格式:int puts(char *str);

str系列字符串操作函数

str系列字符串操作函数主要包括strlen、strcopy、strcmp、strcat等。

  • strlen:统计字符串长度。size_t strlen(chat *str);
    int my_strlen(char a[])
    {
        int i=0;
        while (a[i]) i++;
        return i;
    }
  • strcpy:将某个字符串复制到字符数组中。char *strcpy(chat *to, const char *from);
  • strcmp:比较两个字符串的大小。int strcmp(const chat *str1, const char *str2);
  • strcat将两个字符串连接到一起。char *strcat(char *str1, const *str2);

 OJ练习

统计数字出现的个数

输入N个数(N小于等于100),输出数字2的出现次数。 

#include <stdio.h>

#define N 100

int main() {
    int n, count = 0;
    int a[N];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        (a[i] == 2) ? count++ : 0;
    }
    printf("%d", count);
    return 0;
}

 比较字符串

读取一个字符串,字符串可能含有空格,将字符串逆转,原来的字符串与逆转后字符串相同,输出0,原字符串小于逆转后字符串输出-1,大于逆转后字符串输出1。例如输入 hello,逆转后的字符串为 olleh,因为hello 小于 olleh,所以输出-1。

注意strcmp标准C中并不是返回-1和1,而是负值和正值。

不必反转,直接比较对应相反位置的字符,利用ASCII码进行字符串的大小比较,同时使用二分法遍历。

#include <stdio.h>
#include <string.h>

#define N 100

int main() {
    char info[N];
    gets(info);
    int len = strlen(info);
    int result;
    for (int i = 0; info[i] != 0 && i < len / 2; i++) {
        result = info[i] - info[len - i - 1];
        if (result == 0) continue;
        else {
            (result < 0) ? (result = -1) : (result = 1);
            break;
        }
    }
    printf("%d", result);
    return 0;
}

指针

指针的定义

在内存区域中每个字节都对应一个编号,即”地址”。

在程序定义变量进行编译时,系统会给变量分配内存单元。按变量地址存取变量值的方式称为“直接访问”。

而另一种,将存放变量值的地址放到一种特殊的存放地址的变量中,即指针变量,这种通过指针变量存取变量值的方式称为“间接访问”。

定义格式:基本数据类型 *指针变量名;

  • 指针变量前面的“*”表示该变量为指针变量。
  • 自定义指针变量时必须指定其类型。指针变量的类型必须与存放地址所对应值的类型一致。
  • &和*优先级别相同,但要按照自右向左的方向结合。
  • int *a, b, c;与int *a, *b, *c;不同。

指针变量的初始化是某个变量取地址来赋值,不能随机写数定义。

注意:指针与指针变量是两个概念。

  • 指针:一个变量的地址。
  • 指针变量:存放地址的变量。
  • 指针变量大小:寻址范围为64位即8字节,寻址范围为32为即4字节(考研吗中往往强调程序时32位的)。

 取地址操作符欲取值操作符

取地址操作符为&,也称为引用。用于获取变量的地址值,即指针。

取值操作符*,也称为解引用。用于获取变量中的地址值对应的值。

指针的传递

使用场景一般为函数传参。

C语言的函数调用是值传递,实参赋值给形参。

进程地址空间图:

指针传递即传递地址值(指针)给形参,即可通过形参修改实参值。

指针的偏移

使用场景一般为数组索引。数组名中存储了数组的起始地址。

对指针(地址)进行加减就是指针的偏移。加就是向后偏移,减就是向前偏移,惩处是没有意义的。

 偏移长度是偏移量个基类型长度,因此*(p+i)互相等价于a[i]。void*类型的指针不确定地址对应值的基类型,因此是不能进行偏移的。

程序解析:change函数要对c数组进行修改必须获取到c数组的地址。c作为一个数组名存储了数组的起始地址传递给change函数。

指针与动态内存申请

malloc函数需要头文件<stdlib.h>。

void *malloc(size_t size);

  • size_t为int型变量表示要开辟的内存块的大小(以字节为单位)告诉函数需要动态开辟多少个字节的空间。
  • 返回值为不能便偏移的void*类型的指针,结束后返回给主函数动态开辟好的空间块的首地址,以便后续进行对这块内存空间的使用
  • 向操作空间申请,并分配空间给指针变量时需要强制转换为对应的类型。
  • 指针本身的大小,与其指向的空间大小不同。

释放申请的空间时,必须是malloc返回的地址。

栈的效率比堆高得多,但栈空间是有限的。

注意:函数使用的栈空间在使用完后会被释放,当函数返回指针(地址)时,被释放后的空间会被其它内容覆盖出现乱码。

 堆空间在整个进程中有效,不因为函数调用结束而被消除,只有free才能释放堆空间。

  • 33
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值