今天是2021年9月3日,9月加油啦~
内联函数:
https://blog.youkuaiyun.com/qq_33757398/article/details/81390151
用变量a给出下面的定义 :
(1)一个整型数: int a。
(2)一个指向整型数的指针(一重指针): int *a。
(3)一个指向指针的的指针,它指向的指针是指向一个整型数的指针(二重指针): int **a。
(4)一个有10个整型数的数组 :int a[10]。
(5)一个有10个指针的数组,这10个指针是指向整型数的(指针数组): int *a[10]。
(6)一个指向有10个整型数数组的指针(数组指针):int (*a)[10]。
(7)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(函数指针):int (*a)(int)。
(8)一个有10个指针的数组,这10个指针均指向函数,该函数有一个整型参数并返回一 个整型数(函数指针数组): int (*a[10])(int)。
给了一个地址a,分别强转类型为:int变量、int指针、数组指针、指针数组、函数指针。
int变量 | (int) a; |
int指针 | (int*) a; |
数组指针 | (int (*)[])a; |
指针数组 | (int *[])a; |
函数指针 | (int (*)(int))a; |
在32位系统中,有如下结构体,那么sizeof(fun)的数值是?
#pragma pack(1)
struct fun
{
int i; // 4字节
double d; // 8字节
char c; // 1字节
};
答案:sizeof(fun)得到的结果是13。
解读:因为预处理语句 ”#prama pack(1)” 将编译器的字节对齐数改为1了,根据结构体内存对齐原则,该结构体占用的字节数为13。
求输出结果
int a[2][2][3]= { {{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};
int *ptr=(int *)(&a+1);
printf(“%d %d”, *(int*)(a+1), *(ptr-1));
查看下面代码,p[6]等于几?
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int *p = &a[1];
答案:等于8。
解读:p是一个int类型指针,指向a[1],p[6]表示p往后移了6个单位(每个单位4个字节)并解引用,因此p[6]等于8。
由gcc编译的C语言程序占用的内存分为哪几个部分?
栈区(stack) | 存放函数的参数、局部变量。 |
堆区(heap) | 提供程序员动态申请的内存空间。 |
全局(静态)区(static) | 存放全局变量和静态变量,初始化不为0的全局变量和静态变量、const型常量在一块区域(.data段),未初始化的、初始化为0的全局变量和静态变量在相邻的另一块区域(.bss段)。 |
程序代码区 | 存放函数体的二进制代码和字符串常量。 |
以下程序中,主函数能否成功申请到内存空间?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void getmemory(char *p)
{
p = (char *)malloc(100);
strcpy(p, "hello world");
}
int main()
{
char *str = NULL;
getmemory(str);
printf("%s\n", str);
free(str);
return 0;
}
答案:不能。
解读:getmemory(str)没能改变str的值,因为传递给子函数的只是str的复制值NULL,main函数中的str一直都是 NULL。正确的getmemory()如下:
①传递的是二重指针,即str的指针
void getmemory(char **p)
{
*p = (char *)malloc(100);
strcpy(*p, "hello world");
}
②传递的是指针别名,即str的别名,C++中
void getmemory(char * &p)
{
p = (char *)malloc(100);
strcpy(p, "hello world");
}
在C语言中memcpy和memmove是一样的吗?
答案:
(1)memcpy()与memmove()一样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上。
(2)不同的是,当src和dest所指的内存区域重叠时,memcpy可能无法正确处理,而memmove()仍然可以正确处理,不过执行效率上略慢些。
解读:
(1)memcpy()无论什么情况下,都是从前往后拷贝内存。当源地址在前,目的地址在后,且两个区域有重叠时,会造成拷贝错误,达不到理想中的效果。
void *memcpy(void *dest, const void *src, size_t count)
{
if(dest == NULL || src == NULL || count <= 0) return NULL;
char *d = (char *)dest;
char *s = (char *)src;
while(count--)
{
*d++ = *s++;
}
return dest;
}
(2)memmove()则分两种情况:目的地址在前,源地址在后的情况下,从前往后拷贝内容。否则从后往前拷贝内容。无论什么情况都能达到理想中的效果。
void *memmove(void *dest, const void *src, size_t count)
{
if(dest == NULL || src == NULL || count <= 0) return NULL;
if(dest < src)
{
char *d = (char *)dest;
char *s = (char *)src;
while (count--)
{
*d++ = *s++;
}
}
else
{
char *d = (char *)dest + count;
char *s = (char *)src + count;
while (count--)
{
*--d = *--s;
}
}
return dest;
}
下面代码输出结果是什么?
void main()
{
char *p1 = “name”;
char *p2;
p2 = (char*)malloc(20);
memset (p2, ‘0’, 20);
while(*p2++ = *p1++);
printf(“%s\n”, p2);
}
答案:输出15个’0’。
解读:由于在语句“while(*p2++ = p1++); ”中,p2每次接受p1的赋值之后,都会进行一次自增操作,因此当p1指向的字符串共5个字符(包含’\0’)都赋值给p2后,p2已经指向第六个字符’0’。
指针与引用的区别?
(1)指针是变量,存储的是地址;而引用跟原变量是同一个东西,是原变量的别名。
(2)指针有const;而引用没有。
(3)指针的值可以为NULL;而引用不行。
(4)非const指针可以改变;引用只能在定义时被初始化,之后不可改变。
(5)指针可以有多级,如二重指针;而引用只能有一级。
(6)指针和引用自增(++)的意义不一样,指针自增是地址增加,引用自增是原变量增加。
(7)sizeof指针和引用得到的大小不一样,sizeof(指针)得到的是指针本身的大小,sizeof(引用)得到的是原变量的大小。
a = b * 2; a = b / 4; a = b % 8; a = b / 8 * 8 + b % 4 ; a = b * 15;效率最高的算法?
答案:
a = b * 2 | a = b << 1; |
a = b / 4 | a = b >> 2; |
a = b % 8 | a = b & 7; // 7 = (0b111) |
a = b / 8 * 8 + b % 4 | a = ((b >> 3) << 3) + (b & 3); // 3 = 0b11 |
a = b * 15 | a = (b << 4) - b |
快速排序
https://www.cnblogs.com/lanhaicode/p/10348906.html
进程的地址空间模型?
text segment | 存储代码的区域。 |
data segment | 存储初始化不为0的全局变量和静态变量、const型常量。 |
bss segment | 存储未初始化的、初始化为0的全局变量和静态变量。 |
heap(堆) | 用于动态开辟内存空间。 |
memory mapping space(内存映射区) | mmap系统调用使用的空间,通常用于文件映射到内存或匿名映射(开辟大块空间),当malloc大于128k时(此处依赖于glibc的配置),也使用该区域。在进程创建时,会将程序用到的平台、动态链接库加载到该区域。 |
stack(栈) | 存储函数参数、局部变量。 |
kernel space | 存储内核代码。 |
写出下列线程、互斥锁、信号量相关代码。
定义一个线程ID变量 | pthread_t tid; |
创建线程 | pthread_create(&tid,NULL,pthread_func,NULL); |
等待子线程结束,并回收资源 | pthread_join(tid,NULL); |
与当前进程分离 | pthread_detach(tid); |
退出调用线程 | pthread_exit(NULL); |
取消线程 | pthread_cancel(tid) |
创建互斥锁 | pthread_mutex mutex=PTHREAD_MUTEX_INITIALIZER; |
初始化一个互斥锁 | pthread_mutex_init(&mutex,NULL); |
对互斥锁上锁 | pthread_mutex_lock(&mutex) |
对互斥锁解锁 | pthread_mutex_unlock(&mutex); |
定义一个信号量 | sem_t sem; |
创建信号量并初始化它的值 | sem_init(&sem,0,1); |
信号量的值减1 | sem_wait(&sem); |
信号量的值加1 | sem_post(sem); |
简述TCP三次握手的过程
(1)第一次握手:客户端创建传输控制块,然后向服务器发出连接请求报文(将标志位SYN置1,随机产生一个序列号seq=x),接着进入SYN-SENT状态。
(2)第二次握手:服务器收到请求报文后由SYN=1得到客户端请求建立连接,回复一个确认报文(将标志位SYN和ACK都置1,ack=x+1,随机产生一个序列号seq=y),接着进入SYN-RCVD状态。此时操作系统为该TCP连接分配TCP缓存和变量。
(3)第三次握手:客户端收到确认报文后,检查ack是否为x+1,ACK是否为1,是则发送确认报文(将标志位ACK置1,ack=y+1,序列号seq=x+1),此时操作系统为该TCP连接分配TCP缓存和变量。服务器收到确认报文并检查无误后则连接建立成功,两者都进入ESTABLISHED状态,完成三次握手。
简述TCP四次挥手的过程。
(1)第一次挥手:客户端发出连接释放报文(FIN=1,seq=u),进入FIN-WAIT-1状态。
(2)第二次挥手:服务器收到连接释放报文后发出确认报文(ACK=1,ack=u+1,seq=v),进入CLOSE-WAIT状态。这时客户端向服务器方向的连接就释放了,这个连接处于半关闭状态,服务器还可继续发送数据。
(3)中间状态:客户端收到服务器的确认报文后,进入FIN-WAIT-2状态,等待服务器发送连接释放报文,此时仍要接收数据。
(4)第三次挥手:服务器最后的数据发送完,向客户端发送连接释放报文(FIN=1,ACK=1,ack=u+1,seq=w),进入LAST-ACK状态。
(5)第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认报文(ACK=1,ack=w+1,seq=u+1),进入TIME-WAIT状态。注意此时连接还未释放,必须进过2*MSL(最长报文寿命)的时间,客户端撤销相应的TCB后,才进入CLOSED状态。服务器一旦收到确认报文,立即进入CLOSED状态。
冯·诺依曼结构和哈佛结构异同
https://zhidao.baidu.com/question/53563956.html
不能重载的运算符(5个):
1、. (成员访问运算符)
2、.* (成员指针访问运算符)
3、:: (域运算符)
4、sizeof(长度运算符)
5、?: (条件运算符)
引用与指针的区别
https://blog.youkuaiyun.com/l477918269/article/details/90233908
类型长度
二叉树、前序遍历、中序遍历、后序遍历
https://www.cnblogs.com/lanhaicode/p/10358736.html