c基础每日一问

这是刚自学那会儿每天不懂的疑问都记了下来,学到后来,查查补补,也算一个个勉强弄懂了,记录下,要是有啥问题欢迎大神指出。

1.c各种基本数据类型是否由于操作系统的不同而不同?具体呢?
                  char  short  int  float  double  long  longlong  (单位:字节)
32位平台:  1        2       4      4         8         4           8
64位平台:  1        2       4      4         8         8           8
注:对于各种数据类型,有符号和无符号所占字节一样,只不过有符号的最高位是符号位

2.为什么sigh char类型的127+1=-128?
因为计算机以二进制补码的方式存储,规定整正数的反码、补码和原码一样,负数的反码则是符号 位不变,其余位取反,补码则是反码+1;而8位的sigh char类型127是非符号的全都为1而符号 位为0的0111 1111,对它加1后正数已经越界了,变为1000 0000(此时最高位是1,表示负数),而1000 0000作为补码求其原码的值是-128(实际上严格来说,拿1000 0000去求原码是有问题的,因为10000 0000的符号位不参与加减计算,用它的非符号位去减1求反码根本减不动!于是人为规定1000 0000表示-128,其实当每种有符号基本数据类型的符号位为1,其余位全为0时,都是一种特殊情况)。 实际 上有符号整数在达到正数负数的临界点之前,绝对值是随位数的增多而增大的,过了临界点 之后,绝对值是随着1的位数增多而减小的。如果从0开始每次对sign char值加1经历00000000—> 11111111的过程,它的值的变化是0——>127——>-128——>-1

3.C++对代码的简洁性要求有多高?

4.如何简洁有效地判断任意整数的位数?

5.各种输入函数的区别?scanf()/scanf_s()/getchar()/getch()/gets()

6.各种输出函数的区别?printf/putchar/putch/putc/puts

7.fflush(stdin)可以清理掉前面输入缓冲中剩余的数据(通常是一个换行符\n),因此经常在getchar()
之前使用这个函数,防止getchar()把这个换行符当做有用数据读进变量。
setbuf(stdin,NULL)也是比较常用的

8.while(arr[sizeof(arr)])是否可以?
导致越界访问,但是可以通过编译,因为编译器不检查数组下标是否越界(vs2017对数组仅对只越界1位的情况时会报错),但是无法确定所访问的随机数据是0还是非0。

9.为什么变量赋正值溢出就变成了负数?如果负数溢出呢?
这得从计算机的存储方式是二进制补码说起,详见上面问题2。负数是溢出则变成0

10.常见的排序?

11.各种变量的内存分配问题?
全局变量(包括静态和非静态)和静态局部变量在编译时期分配内存,程序运行完释放;非静态局部变量在程序运行到定义它的那一行时分配内存,程序退出其所指在函数时释放内存。

12.各种的变量的作用域问题?
非静态全局变量在整个工程下可见,静态全局变量在当前文件可见,静态和非静态局部变量在其所在最近的{ }内可见,但要注意,静态局部变量只初始化一次,当程序离开其所在代码块或函数时并不释放,而是等整个程序运行完才释放。

13.return放在函数末尾,如果后面接一个值或式子,表示函数返回一个值,如果 后面空的什么也不接,则单纯起到离开函数的作用。return起到离开当前函数的作用,而exit则起到结束程序的作用,即使当它放在分函数时。

14.return返回值原理:当返回值不大于4个字节,被调函数返回值暂存在EAX寄存 器中,当返回值大于4个字节时,32位的寄存器放不下,被暂存在主调函数的某个 内存空间。

15.c语言中内存区详情?
c语言大概分4区,由地址从低到高分别是:代码区、静态常量区、堆区、栈区
代码区:存放的是程序代码,并且只读
静态常量区:地址由低到高分别是:文字常量区、data区(已初始化的全局、静态变量)、bss区(未初始化的全局、静态)
堆区:由malloc( )手动申请的空间
栈区:局部的非静态变量

16.为什么函数声明一般放在最上面?一般情况下,被调函数的代码放在主调函数 的上方就可以成功调用,这叫函数的可见性。函数声明为了使所有的函数都具有可 见性。

16.磁盘永久存储,内存暂时存储,CPU用于计算.

17.不同源文件里函数的相互调用
要调用同一个工程下的其他文件的非静态函数,只需保证该函数可见性,在主调函数的上方给出被调函数的声明即可。

20.不同源文件中相互调用全局变量只需用extern声明

21.全局变量和静态变量的区别?
全局变量在进入程序前就已经被加载进内存,静态局部变量在进入函数时加载进内存,
但函数完成退出时,静态局部变量保留。两者存储区一样。static可以用于区分不同
源代码内的同名变量。

24.实际开发中,局部变量和全局变量哪个用得多?
《c primer plus》第5版的一段原话:“为什么选择自动类型作为默认类型?是的,乍看起来外部存储很有诱惑力。把变量都设成外部变量,就不用为使用参数和指针在函数之间传递数据而费心了。然而,这存在着一种不十分明显的缺陷,你将不得不为函数A( )违背了你的意图,偷偷修改了函数B( )所用的变量而焦急。多年来,无数程序员的宝贵经验给出了无可置疑的证据。证明了随意使用外部变量带来的这一不十分明显的危险远比它所带来的表面吸引力更致命。”

26.一个字符占一个字节会不会不太够?是不是因系统不同而改变标准?

28.EOF和feof()的区别?

EOF仅仅只是个值为-1的宏,因为大部分文件读取函数读取失败(读到文件结尾无内容可读也是读取失败的一种,而且其他情况的读取失败很少出现)的返回值是-1。但EOF只能用于读取文本文件,因为文本文件的字符都是以ASCII码值存储的,不存在-1的ASCII码值,而二进制文件就不同了

feof()就是为二进制文件而生的,它即可用于文本文件,又可用于二进制文件,它是根据FILE型结构体的用于标记是否读到文件结尾的成员变量的值来判定文件是否已经读到结尾的,但文件内部指针指向文件结尾时,FILE结构体的负责标记的成员并未立即置位,而是要等文件读取函数再读取一次才进行置位。

当读取键盘输入时,Windows中,需要单独一行Ctrl+Z+Enter才能模拟出EOF效果

29.getchar()只能读取单个字符,例如输入15,也是分‘1’和‘5’两次读取。

32.通过printf()/scanf()等函数从屏幕上读取和输出数字其实都是以字符的形式,但 相关函数会自动转换成对应的类型,如printf("%d",8);实际上屏幕上显示的是字符型 的“8”,又如scanf("%d",&num);实际上函数自动把屏幕上输入的字符型“8”转化为 数字型的8,再进行存储。有时需要把字符型数字转化为数字型可以使用atoi()/atof() /atol()/strol()等函数

33.为啥字符串作为函数参数时,该函数内部能用strlen(s)取得字符串长度却不能用 sizeof(s)/sizeof(s[0])? 因为字符串做参数时,传给函数的是其首字符的地址。strlen()的工作原理是通过改地 址从s[0]开始计算字符数量直至遇到结尾的空字符‘\0’;而sizeof()则是求得参数 本身所占的字节大小,当一个指针P作为参数时,得到的是这个指针的字节大小,而不 是这个指针所指的对象的字节大小

34.使用srand(time(NULL))和rand()产生随机数

35.正整数和负整数在计算机中的存储?
在计算机中数据均是以二进制并且是反码形式存储的,这是为了保证表示一个十进制的二进制码只有一个,这些二进制有原码、反码、补码等,并且规定正数的反码、补码和原码一样。那么负数则是(以char类型的-7为例):
原码:绝对值直接转的二进制,最高位符号位置为1(符号位0表正数,1表负数) ——————>1000 0111
反码:在原码基础上,符号位不变,其余位取反      —————————————————>1111 1000
补码:反码+1                                     ——————————————————————>1111 1001
(注:符号位是不参与加减的,如果加减导致数据位的最高位已经要向前进位或借位了,那么已经溢出了)

36.c中printf("%d%d",a++,++a)两个式子都是先运算再打印,而java中则按++的位置 来,据说和不同的编译或运行平台有关(有些编译器的优化方式不同)

37.二进制读写文件和文本读写文件的区别?
按文本模式读取是把内存中的二进制按每8位转成其ASCII码值所对应的字符,再显示出来;按文本模式写入则是把文件中的每个字符均转为其ASCII码值的二进制形式,再放入内存。
二进制则是直接当做二进制

38. 如果以“文本”方式打开一个文件,那么在读字符的时候,系统会把所有的“\r\n”序列转成“\n”,在写入时把“\n”转成“\r\n”。

39.编译器最终把数组形式换为指针形式,再由于c/c++中一个数组的元素都是连续空间 存储的,所以通过arr[0][7]和arr[1][0]均能访问数组的第二行第一个元素。


40.如果不同函数里的字符型指针赋值时使用的是相同的字符串常量,c++编译器代码优 化时会只提供一份存储空间用来存储该字符串常量(例如:function1(){char *p1= "abcd"}和function2(){char *p2="abcd"},编译器优化之后只在全局区存储一份“ abcd”)

41.计算机中,数值均以补码形式存储,正数的原码、反码、补码相同。负数的反码等于原码符号位不变 其余位取反,补码等于反码+1。所以欲把计算机存储的二进制转换为它所表示十进制数值的一般 步骤是:1)先看这个数是有符号数还是无符号数,若是正数,则直接转化为十进制;2)若为负数, 则最高位不变,-1得到其反码(注意符号位不参与加减,如果数据位的最高位需要向前面借位,则说明溢出了),然后最高位不变,其余位全部取反,然后转化为十进制并添加负号。

1)unsigned char a在计算机中的存储形式是1000 0001,问a里存储的十进制数是多少? a是无符号数,求其原码即等于补码1000 0001,直接转换为十进制:129

2)char b在计算机中的存储形式是1000 0001,问a里存储的十进制数是多少? b是有符号数,补码1000 0001,反码1000 0000,原码1111 1111,转换为十进制:-127

42.scanf("%*c%s",s)中,*表示跳过,%*c表示跳过一个字符,若为%*5s则表示跳过5个字符

43.字符串数组只有在初始化的时候可以通过=整体赋值,其它时候只能通过strcpy或memcpy 之类的函数操作内存整体赋值,但结构体可以,结构体的整体赋值的=实现原理其实就类似 于memcpy,所以当把数组放入结构体也能实现整体赋值。

44.fopen()的第二个参数:   r可读    r+可读可写    w可写有就清零,没有就创建      w+可读可写有就清零,没有就创建      b表示 以二进制形式读写,不写b则表示默认文本形式

45.gets()不读换行符,puts()自动添加换行符,他俩配对
fgets()读取换行符,fputs()不添加换行符,他俩配对


46.刷新缓冲区的三种情况:1)缓冲区满自动刷新;2)程序正常退出时;3)fflush(fp) 强制刷新。
另:标准输入输出可以使用行缓冲\n;  close(fp)关闭文件流也会刷新缓冲区。

47.scanf(“%*[^\n]%*c”)和while(getchar()!='\n');等效

48.
scanf()通过格式控制符%d把键盘输入的字符型整数转成整型整数存入整型变量中
fscanf()通过格式控制符%d把从文件中读取的字符型整数转成整型整数存入整型变量中

printf()通过格式控制符%d把整型整数转为文本字符型输出在屏幕上
fprintf()通过格式控制符%d把整型整数转为文本字符型输出到文件中

49.通过数组和指针访问的区别:(1)编译器符号表中,数组名arr具有一个地址,这个地址+偏移量,再取里面的内容即取得里面的元素;(2)编译器符号表中,指针名p自身具有一个地址1,取这个地址1里存储的一个地址2,再对地址2+偏移量,再取里面的内容,得到该元素。

50.
int main(void)
{
    int a = 1;
    int *p = NULL;
    p = &a;
    int i = 0;
    i[p] = 3;//数组下标的形式编译时都被编译器转换为指针形式 i[p]------>*(i+p)------>*(p+i)
    printf("%d%d", *p, i);
    system("pause");
    return 0;
}

51.
栈的使用从高地址开始往低地址跑(堆则相反)。一般arm是使用小端模式,高地址放高位字节,低地址放低位字节,所
以例如0x12345678往栈区存储时,地址由高到低,依次存入12,34,56,78

52.
int a=(int)&(p->age);得到结构体成员的实际地址
int b=(int)&(((Teacher)0)->age);得到该结构体成员地址相对于结构体起始地址的偏移量
(其中Teacher为一结构体,p为指向该结构体的指针)
或者 int c=(int)&(p->age)-(int)p;也得到偏移量

53.结构体对齐单位

获取对齐单位,以下三个因素决定
1.CPU周期
WIN vs qt 8字节对齐
Linux 32位 4字节对齐,64位8字节
2.结构体最大成员
3.#pragma pack(n) n--只能填1 2 4 8 16
上面三者取最小的,就是对齐单位

存放规则:
1.第一个成员放在偏移量为0的位置,大小就是数据类型的大小
2.下一个成员存放的起点,必须该成员大小的整数倍(意思就是前面成员占的空间是这个成员所占空间的整数倍)
当成员类型大于对齐单位,计算该成员的起点,以对齐单位计算
3.结构体整体的大小必须是对齐单位的整数倍

54.
数据结构:
(1)动态数组:
一个指针数组顺序存储外来数据的地址
(2)链表实现动态数组
函数内部自增或自减链表节点,每个节点需要存储客户资料和下一个节点的地址
(3)linux内核链表
函数内部自增自减链表节点,但仅需头节点需要自身开辟空间用于存储客户第一个结构体的地址,后面的节点空间均由客户提供。

猜你喜欢

转载自blog.csdn.net/m0_37829435/article/details/80153221