程序的局部变量存在于栈区,全局变量存在全局区(静态区),动态申请的数据存在于堆。
类型 | = | ≠ |
---|---|---|
bool类型 | if(flag) |
if(!flag) |
int类型 | if(val == 0) |
if(val != 0) |
浮点数类型 | if(x >= 0) |
if(x <= 0) |
指针类型 | if(ptr == NULL) |
if(ptr != NULL) |
数据类型 | 16位机 | 32位机 | 64位机 |
---|---|---|---|
bool | 1 | 1 | 1 |
char | 1 | 1 | 1 |
short | 2 | 2 | 2 |
int | 2 | 4 | 4 |
long | 4 | 4 | 4 |
long long | / | 8 | 8 |
float | / | / | 4 |
double | / | / | 8 |
long double | / | / | 12 |
指针 | 2 | 4 | 8 |
注:标注“/”符号表示我目前还不清楚
当字符型数向整型数赋值时,是将十进制数值赋值过去,而不是二进制位赋值
int main(){
int i;
char c=0x80; //c=-128;
i=c;//i=-128
if(i>0) printf("%s",">0");
else printf("%s","<=0");
return 0;
}
该程序运行后输出:
<=0
根据C/C++语言中的整数自动转换原则:当表达式中存在有符号类型和无符号类型时,所有的操作数都自动转换为无符号类型
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts(" <= 6");
}
运行程序后输出:
> 6//结果输出
算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符
逻辑运算符中“逻辑非 !”除外
优先级问题 | 表达式 | 误认结果 | 实际结果 |
---|---|---|---|
++等于* | *p++ | *(p++) | (*p),p++ |
++等于* | *++p | (*p)++ | *(p++) |
*高于+ | *p+4 | *(p+4) | (*p)+4 |
[] 高于 * | int *ap[] | int (*ap)() | int *(ap[]) |
. 高于 * | *p.f | (*p).f | *(p.f) |
在实际编程中,记不住优先级高低也没关系,加个括号()就行了,因为括号优先级最高
int main(){
char *p = {"964ltdswa"};
printf("%c ",*p+4);
printf("%c ",*p++);
printf("%c ",*p);
return 0;
}
运行程序后输出:
= 9 6
功能:返回对象所占用的内存空间,但不能返回动态分配内存空间的大小
struct size{
int a;
char b;
double c;
}
sizeof() = 16;
struct size{
char digit:4;//位域,仅用4个位表示,位域不能跨字节,最多为8位
char index:4;
unsigned short data:8;
unsigned short;
}
sizeof() = 4;
struct size{
char a;
char b;
char c;
}
sizeof() = 3;
struct size{
double a;
short b;
int c;
char d;
}
sizeof() = 20;
struct size{
}
sizeof() = 1;
union size{
int a;
double b;
}
sizeof() = 8;
char str[] = "abc";
sizeof(str) = 4;
//
char a[10];
sizeof(a) = 10;
char a = 8;
char *p = &a;
sizeof(p) = 4;
//
char **str = "abcdef";
sizeof(str) = 4;
//
char a[10];
char *pt = a;
sizeof(a) = 10;
sizeof(pt) = 4;
//
int *a = (int*)malloc(10*sizeof(int));
sizeof(a) = 4;//返回指针大小
示例程序如下:
int main(void)
{
int a,b,c,d;
a = 9;
b = a++; //b=a=9,a++
c = ++a; //a++;c=a=11;
d = 10*a++; //d=10*a=10*11,a++;
printf("%d, %d, %d",b, c, d);
return 0;
}
运行程序后结果如下:
9 11 110
特别情况:
int main(void)
{
int a,b,c;
a = 2;
b = 3;
c = a+++++b;
printf("%d, %d, %d",b, c, d);
return 0;
}
程序运行后,会出现这样的结果:
error: lvalue required as increment operand
因为“a+++++b”这一段根本就无法解析,编译系统从左至右扫描整条语句,首先遇到a++,判断出来是一个a的后缀自加运算,然后接着扫描,遇到一个+,+是一个二目运算符,它的左边已经有一个运算数a++了,系统就继续向右搜索,然后又遇到一个+,++比+的运算级别要高,这时,编译系统就将两个+看成一个整体来处理,既然是++,编译系统就认定,肯定它的左边或右边有一个变量,编译系统先搜索左边,发现++,不是变量,再搜索右边,发现+b,+b是什么怎么回事呢?编译系统是无法搞明白的,因此它就认为++是一个缺少左值的自增运算符,于是提示提示用户:error!
但是以下情况是可以计算出结果的:
int main(void)
{
int a,b,c,d,e,f,g,h,i;
a = c = e = 3;
b = d = f = 2;
g = a++ + ++b;
h =(c++)+(++d);
i = e+++f;
printf("%d, %d, %d",g, h, i);
return 0;
}
程序运行后结果输出:
6 6 5
字符串定义有三种方式,字符串字面量,char类型数组,指向char类型的指针;
"I am a symbolic stringconstant."
"I am a string in an array."
"Something is pointed at me."
"Here are somestrings:"
const char * pt1 = "Something is pointing at me.";
const char ar1[] = "Something is pointing at me.";
#define MSG "I'm special"
#include
int main()
{
char ar[] = MSG;
const char *pt = MSG;
printf("address of \"I'm special\": %p \n", "I'm special");
printf(" address ar: %p\n", ar);
printf(" address pt: %p\n", pt);
printf(" address of MSG: %p\n", MSG);
printf("address of \"I'm special\": %p \n", "I'm special");
return 0;
}
运行该程序后的输出:
address of "I'm special": 0x100000f10
address ar: 0x7fff5fbff858
address pt: 0x100000f10
address of MSG: 0x100000f10
address of "I'm special": 0x100000f10
该程序的输出说明:第一,pt和MSG的地址相同,而ar的地址不同。第二,字符串字面量"I’m special"在程序的两个 printf()函数中出现了两次,但是编译器只使用了一个存储位置,而且与MSG的地址相同,说明编译器可以把多次使用的相同字面量储存在一处或多处。第三,静态数据使用的内存与ar使用的动态内存不同,不仅值不同,特定编译器甚至使用不同的位数表示两种内存。
在C语言中,一个字符除了可以用它的实体(也就是真正的字符)表示,还可以用编码值表示,每个字符都有其唯一对应编码值。这种使用编码值来间接地表示字符的方式称为转义字符。转义字符以\或者\x开头,以\开头表示后跟八进制形式的编码值,以\x开头表示后跟十六进制形式的编码值。对于转义字符来说,只能使用八进制或者十六进制。
int main(){
puts("\x68\164\164\x70\x73://csdn.\x6e\145\x74");
return 0;
}
//运行结果
https://csdn.net
转义字符取值范围
void指针可以指向任意数据类型,也可以接受任意类型的指针对void指针幅值,但是void指针接受一种类型的指针赋值后,不能再接受其他类型的指针赋值
int *a;
void *p;
char *s;
p = a;//正确
p = s;//错误
形如"ptr+x"的结果等于"ptr+x*sizeof(ptr)"
unsigned char *p1;
p1 = (unsigned char*)0x08000100;
p1+5 = 0x08000105;
//
long int *p2;
p2 = (long int*)0x81000000;
p2+5 = 0x81000014;//0x代表十六机制
(int*)0x81001254
(char*)0x80254618
//设置一绝对地址为0x67a9的整型变量的值为0xaa66
*((int*)0x67a9) = 0xaa66;
//让程序跳到绝对地址0x100000去执行
//有以下两种格式
(*(void(*)(void))0x100000();
((void(*)(void))0x100000();
1、首先void(*)(void)是指向函数的指针,可用于强制类型转换
2、把0x100000转换为函数指针,(void(*)(void))0x100000
3、进行函数调用(跳到地址去执行)(*(void(*)(void))0x100000)();
4、设void func(void){},func为函数名,也是函数体首地址
5、令void(*func_p)(void) = func;
6、(*func_p)();和(func_p)();的执行结果是一样的,看到其他人有说第二种属于历史遗留问题;
7、可知第二种不加*号也可
int a; //一个整型数
int *a; //一个指向整型数的指针
int **a; //一个指向指针的指针,它指向的指针指向一个整型数
int a[10]; //一个有十个整型数的数组
int* a[10]; //一个有十个指针的数组,每个指针指向一个整型数
int (*a)[10]; //一个指向有十个整型数的数组的指针
int (*a)(int); //一个指向函数的指针,该函数有一个整型参数,并返回一个整型数
int (*a[10])(int) //一个有十个指针的数组,每个指针指向一个函数,该函数有一个整型参数,并返回一个整型数
上述指针同样适用于其他数据类型,并且对于字符型指针数组某一元素还可以这样表示索引:
main() {
char *str[]={"ab","cd","ef","gh","ij","kl"};
char *t;
t=(str+4)[-1];
printf("%s",t);
}
程序运行后输出:
gh
假设有如下声明:
int *pt; // pt一个指向指针的指针
int (*pa)[3]; // pa一个指向内含3个int类型元素数组的指针
int ar1[2][3]; // ar1一个指向内含3个int类型元素数组的指针
int ar2[3][2]; // ar3一个指向内含2个int类型元素数组的指针
int **p2; // p2一个指向指针的指针
int a3[3]; // ar3一个指向int的指针
有如下的语句:
pt = &ar1[0][0]; // 都是指向int的指针
pt = ar1[0]; // 都是指向int的指针
pt = ar1; // 无效,类型不匹配
pt = ar3; // 都是指向int的指针
pa = ar1; // 都是指向内含3个int类型元素数组的指针
pa = ar2; // 无效,类型不匹配
pa = &a3; // 都是指向内含3个int类型元素数组的指针
p2 = &pt; // 都是指向指针的指针
*p2 = ar2[0]; // 都是指向int的指针
p2 = ar2; // 无效,类型不匹配
进一步地,若有以下地址:
ar1 = 0x68f438;
ar3 = 0x79d536;
则可得:
ar1[0] = 0x68f438;
ar1+1 = 0x68f444;
ar1[0]+1 = 0x68f43c;
ar3[0] = 0x79d536;
ar3+1 = 0x79d53a;
&ar3+1 = 0x79d542;