周报日常:易错题

1.结构体内存对齐:

#include<stdio.h>
struct a{
    int a;
    int b;
    char c;
    double d;
}aa;
int main()
{
printf("%d ",sizeof(aa.a));
printf("%d ",sizeof(aa.d));
printf("%d ",sizeof(aa.c));
printf("%d ",sizeof(aa.d));
printf("%d",sizeof(aa));
return 0;
}

程序输出为:

4 4 1 8 24

其中32位操作系统:
char : 1 int :4 short : 2 unsigned int : 4 long : 4 unsigned long : 4 long long : 8 float : 4 double : 8 指针 : 4
64位操作系统
char : 1 int :4 short : 2 unsigned int : 4 long : 8 unsigned long : 8 long long : 8 float : 4 double : 8 指针 : 8
内存对齐:
每个参数按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍。不够就补空字节。
内存对齐主要遵循下面三个原则:

1.结构体变量的起始地址能够被其字节最长的参数大小整除
2.结构体每个参数相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个参数后面补充字节
3.结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节
4. 如果嵌套了结构体的情况,被嵌套的结构体对齐到其自身对齐数的整数倍处(结构体的对齐数就是其内部成员中最大的对齐数),此时结构体的整体大小就是所有最大对齐数(含被嵌套结构体的对齐数)的整数倍。

第一个是int 型四个字节,占0x0000-0x0003,第二个int型占0x0004-0x0007,第三个char型占0x0008-0x0009第四个double型8字节,为满足原则2,应占0x0017-0x0024,所以char补齐7个字节。且24%8==0满足原则三,
即int(4)+int(4)+char(1)+补齐(7)+double(8)=24
当b和d换位结果相同。

再来一个例子

struct S1
{
	char c1;
	short c2;
	int i;
}S;
struct S2
{
	char c1;
	struct S;
	double d;
};

struct s1长度char(1)+short(2)+补齐(1)+int(4)=8
struct s2长度char(1)补齐(3)+struct(8)+补齐(4)+double(8)=24

2.头文件的使用和指针使用字符串

#include<stdio.h>

int main()
{
    char s[] = "Hello,Xiyounet!";
    char *s2;
    strcpy(s2,s);
    printf("%s",s2);
    return 0}

改为:

#include<stdio.h>
#include<string.h> 
int main()
{
    char s[] = "Hello,Xiyounet!";
    char *s2;
    char *ss=s;
    strcpy(s2,ss);
    printf("%s",s2);
    return 0;
}

3.函数的声明和参数存在的范围
如下程序

int main()
{
    f();
    return 0;
}
char *f()
{
    char s[] = "hello,world!";    
    return s;
}

在使用函数应先在main函数前进行声明,定义它的类型。
在函数使用中不能返回函数内部定义的值,如要使用需加入static全局变量。
4.函数的调用

void sum(int a,int b){
    printf("%d", a+b);
}

int main()
{
    int a=1,b=2;
    void sum(a,b);
    return 0;
}

在使用函数时不用void。
5.指针不可修改

char * s="Hello,Xiyounet!";
printf("%s",s);
s[0]='h';
printf("%s",s);

可修改为

#include<stdio.h> 
int main()
{
   char sz[]="Hello,Xiyounet!";
	printf("%s",sz);
	char *p=sz;
	*p='h';//p[0]='h';
	printf("%s",p);
}

输出为:Hello,Xiyounet!hello,Xiyounet!
6.main函数的参数是什么?如何给main函数传递参数?**
(1)通过命令参数传递参数;
习惯上这两个参数写为argc(argument count)和argv(argument vector)
argc是个整形变量,命令行参数个数,
char *argv[]是字符指针数组,
argv[0] 为程序运行的全路径名
argv[1] 为在DOS命令行中执行程序名后的第一个字符串;
argv[2] 为执行程序名后的第二个字符串;
argc:argc是执行程序时的命令行参数个数。需要注意的是,程序本身的文件也算一个。例如你在命令参数里写了2个参数,那argc等于3。
argv[]:存的是命令行参数(字符串)的首地址,包括程序本身的文件和尾部的dull。
在项目——》属性——》配置属性——》调试——》命令参数,设置命令参数就可以传入参数

int main(int argc, char *argv[], char *envp[])
{
    int i = 0;
    for (i = 0; i < argc; i++)
    {
        printf("%s\n", argv[i]);
    }
    return 0;
}

输出值即为你设置的参数。

envp里存放正是系统的环境变量,可以右键单击计算机——》属性——》高级系统设置——》环境变量,打开环境变量设置窗口

#include<stdio.h>
#include<Windows.h>
int main(int argc, char* argv[], char* envp[])
{
    int i = 0;
    while (envp[i] != NULL)
    {
        printf("%s\n", envp[i]);
        i++;
    }
    system("pause");
    return 0;
}

7.c和.cpp文件是如何变成可执行文件的?**
一.预编译:

  1. .处理源代码文件中的“#”开始的预编译指令。如“#include”、“#define”等。具体如下:
    1. 宏替换:将所有的“#define”删除,并展开所有的宏定义。 处理条件预编译指令:如“#if" “#endif” “#elif” "#else"指令:
    2. 处理“#include”预编译指令,将被包含的头文件插入到预编译指令的位置。(递归插入,被包含的文件还可能包含其他文件)
    3. 删除所有注释(“//”、“/* */”)。 添加行号和文件标识(以便编译时期,出错显示行号、调试使用行号信息)
    4. 保留所有#pragma编译器指令。

二.编译:

  1. 词法分析:源代码经过扫描器,将源代码的字符序列分割成一系列的记号(关键字、标识符、字面量(数字、字符串)、特殊符号(如“+”“-”)),同时将标识符存放到符号表,数字、字符串常量放到文字表等工作,以备后续使用。
  2. 语法分析:语法分析器对扫描器产生的记号进行语法分析,生成语法树(以表达式为节点的树,检验表达式的逻辑性)。
  3. 语义分析:对静态语义(编译期可以确定的语义,包括声明、类型匹配、类型转换等)进行分析。如浮点型表达式赋给整型表达式时,类型不匹配,语义分析隐含执行了浮点型到整型转换的过程。
  4. 代码优化:源代码级优化器(优化语法树,如替换重复或简单的表达式)进行优化。

三.汇编:汇编器将汇编代码变成机器可以执行的指令
四.链接:空间与地址分配,符号解析与重定位。
8.范围
unsigned int 的范围为0~65535//32767+32768
unsigned char的范围为0~255
9.左移运算符, 右移运算符,取反规则

printf("%d",~9;
printf("%d",(-9)>>1);
printf("%d",(-9)<<1);

-9二进制为原码10001001补码为01110111
左移运算符左移补零,10010010,即为-18
右移运算符因为负数右移补一,10000101,即为-5
取反~1 = 0, ~0 = 1
~(01110111)=10001000即为8

10.&&和&

int i=0;
int j=0;
int ii = i++ && ++j;
printf("%d %d %d\n", ii, i, j);

i = 0;
j = 0;
ii = ++i & j++;
printf("%d %d %d\n", ii, i, j);

输出:
010
011
原理:
1.&&
只要左端条件式为假直接不成立,不会去判断右端条件式。
相同点:只要有一端为假,则语句不成立,即ii = i++ && ++j;当i=0时不在执行j的命令所以j输出为0。
2.&
&左右两端条件式有一个为假就会不成立,但是两端都会运行,比如 ii = ++i & j++;i=0即使为假,也会去判断是否成立。即j自增。
另:strlen只计算\0之前的字符。

实数格式识别 【问题描述】 合法的实数书写格式分一般格式和科学格式两种。分别描述如下: 一般格式为常见的书写格式,分为整数部分和小数部分两部分,中间分用小数点.分隔。整数部分最开始可能含有正号或负号,之后为不含前导零的数字串;小数部分是由0-9十种字符组成的任意长的字符串。当小数部分为0时,小数部分和小数点可以省略。 科学格式由系数部分和指数部分两部分组成,中间用英文字母E分隔。系数部分为实数书写的一般格式;指数部分为可带有正负号数字串。 例如,+2、-1.56为一般格式的实数,而6.2E-2、-9E8为科学格式的实数。 只有小数点而没有小数部分的书写格式为不合法,例如,23.,23.E16均为不合法的实数书写格式。 编程分析哪些数的书写是正确的,是用哪种方式书写的。 【输入形式】 输入文件为当前目录下的real.in。 该文件包含一个字符串(长度不超过20个字符),以回车符结束,表示一个数据(无多余空格)。 【输出形式】 输出文件为当前目录下的real.out。 该文件有一行。如果输入数据的书写是非法的,输出Wrong;如果输入数据是用一般格式书写的,输出“Format1”;如果该数据是用科学格式书写的,输出“Format2”。输出的末尾均要以一个回车符作为结束。 【输入样例1】 +1.23 【输出样例1】 Format1 【输入样例2】 -5.1.1 【输出样例2】 Wrong 【输入样例3】 -5.1E-2 【输出样例3】 Format2 【时间限制】 1s 【空间限制】 65536KB
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值