1.左值和右值是什么?
左值是指出现在等号或者表达式左边的变量,一般来说就是它的值可以改变;
右值是指出现在等号的右边的变量或者表达式,它重要特点是可读;
通常下,左值可以做右值,右值不能做左值
a++不能进行左值运算比如:
i++ = 5;
2.什么是电路求值
demo:
int main()
{
int a=2;
int b=3;
if(a>0 || b++>2) //b++>3这个的优先级:先进行判断b>3,再b+1;
{
printf("%d\n",b); //b=3,
//解释:在if里面有||条件,只要满足其中一个就认为满足条件,就不再需要判断另个语句,也就是说b++并没有执行
}
if(a<0 || b++>2)
{
printf("%d\n",b); //b=4,
//解释:在if里面有||条件,只要满足其中一个就认为满足条件,就不再需要判断另个语句,但第一个条件并没有满足,所以就会执行b++
}
if(a>0 && b++>2)
{
printf("%d\n",b); //b=5,
//解释:在if里面有&& 条件,只有满足第一个条件才会去判断剩下的条件,第一个条件满足,所以就会执行b++
}
if(a<0 && b++>2)
{
printf("%d\n",b);//b=5,//解释:在if里面有&&条件,只有满足第一个条件才会去判断剩下的条件,第一个条件不满足,也就是说b++并没有执行
}
printf("%d\n",b);
return 0;
}
3a++和++a 区别
1.a++是先把a赋值到一个临时空间,再对a+1赋值给临时变量,等运算结束后才返回临时变量给a (参与运算的是自加之前的值)
解析:i++相当于i = i+1
等号右边的为右值,只能读,不能写,即右边的i只能读出放到一个临时变量里面,在这个临时变量里面进行+1操作之后,再赋值给等号左边的 i
2.++a是先给 a+1,直接对a赋值,不需要开辟临时空间(参与运算的是返回值的引用)
3.a++需要开辟空间,等运算完才返回值,所以效率比++a低
做自加和后自加题目之前要先明白以下几点:
1.无论是前自加还是后自加都是函数调用,都有返回值,返回值就是我们需要用来运算的
2后自加的返回值是自加前的值
3.前自加的返回值是该变量的引用不是具体的数值,做运算的时候才确定(比如+ - / % *)
4.所有的运算都是返回值的运算
比如:
int i = 1;
printf("%d\n",++i / i--);
左边的++i的返回值是变量i的引用,这个时候 i = 2,右边i--返回的是做--之前的数值即2,这个时候i = 1,也就是说i的引用为1,即 1 / 2 = 0
4.局部变量能不能和全局变量重名
能,局部变量会屏蔽全局变量,比如在一个函数里定义一个变量int a =2,在外面定义全局变量int a =1;那么在该函数里操作的是局部变量
如果想使用全局变量,可以使用{ extern int a }形式
全局变量可不可以定义在可被多个.C文件包含的头文件中 ? 为什么?
可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
5.gets 和 scanf函数的区别 (空格,输入类型 ,返回值)
1)gets函数可以接受空格,scanf遇到空格就会结束
2)gets函数仅用于读入字符串;scanf为格式化输出函数,可以读入任意C语言基础类型的变量值,而不是仅限于字符串(char*)类型
3)gets的返回值为char*型,当读入成功时会返回输入的字符串指针地址,出错时返回NULL;
scanf返回值为int型,返回实际成功赋值的变量个数,当遇到文件结尾标识时返回EOF
6.C语言编译过程中,volatile关键字和extern 关键字分别在哪个阶段起作用?
volatile预处理,因为代码优化是在编译,extern 在链接
7. char *str1 = "hello " 和 char str2[ ] = "hello"
数组名 相当于常量指针,只可以修改数组里面的元素,不可以修改数组的地址即不能str++
字符指针 相当于是指针常量,不可以修改指向的地址的内容,可以修改地址
char str[] = "hello";
char *str1 ="hello";
//区别一 数组名不可以自加,因为数组名是地址常量
//str++;
//str1++;
//区别二 ,数组里面的元素可以修改,str1指向的地址的内容不可以修改
str[0] = 'W';
*str1 = 'w';//段错误
总结: 数组名就相当于是常量指针,只可以修改里面的内容,不可以修改指向的地址,字符指针相当于是指针常量,不可以修改指向的地址的内容,可以修改地址
8.局部变量与全局变量同名的时候如何使用全局变量
方法1:使用函数,把全局变量包到里面,作为返回值
方法2:使用{ extern 全局变量 };
#include<stdio.h>
int a = 20 ;
int main ()
{
int a = 10;
printf("%d \n" ,a); // 10
{
extern int a;
int temp = a;
printf( "%d \n",temp); // 20
}
printf( " Hello world! \r\n")' //Hello world
return 0;
}
代码随想录
1.链表理论基础
链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思);链表的入口节点称为链表的头结点也就是head。
链表的类型: 单链表(普通链表)
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。双链表 既可以向前查询也可以向后查询。
循环链表 :就是链表首尾相连。循环链表可以用来解决约瑟夫环问题。
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。
所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理
链表的定义:
struct LinkNode{
int value;
LinkNode * next;
LinkNode(int x): value(x),next(NULL) {}
};
使用默认构造函数初始化节点:
LinkNode * head = new LinkNode();
head -> value = 5;
所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值
链表的操作 :
删除节点
添加节点
可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。
但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)
2.移除链表元素
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。 ![](https://img-blog.csdnimg.cn/411070929dc74b2396732afaf73d71fd.png)
707. 设计链表 难度中等
你可以选择使用单链表或者双链表,设计并实现自己的链表。假设链表中的所有节点下标从 0 开始。
206. 反转链表 难度 简单
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
链表的操作问题,一般而言面试(机试)的时候不允许我们修改节点的值,而只能修改节点的指向操作。
思路通常都不难,写对链表问题的技巧是:一定要先想清楚思路,并且必要的时候在草稿纸上画图,理清「穿针引线」的先后步骤,然后再编码。