【咬文嚼字】c语言中你可能不知道的小知识(2)

前言

作为一名c语言萌新,在学习完c中的基本语句后,就能写出一些小的c语言程序了,但在写的过程中可能总是会碰到一些小地方困扰着你,因此我决定写下这篇文章记录下我遇到的一些小问题帮助你查漏补缺,并扫清那些你记忆中模棱两可的地方。


一、printf

请问一下代码在屏幕上输出什么?

#include<stdio.h>

int main()
{
	int a = 12;                 
	printf("*%d*\n", a);        //用两个'*'知识为了方便给
	printf("*% d*\n", a);       //大家呈现具体结果,只用回答
	printf("*% d*\n", -a);      //*里的内容就行

	printf("*%5d*\n", a);
	printf("*%-5d*\n", a);
	printf("*%05d*\n", a);

	printf("*%+d*\n", a);
	printf("*%+d*\n", -a);

	printf("*%x*\n", a);
	printf("*%#x*\n", a);
	return 0;
}

答案:

*12*
* 12*
*-12*
*   12*
*12   *
*00012*
*+12*
*-12*
*c*
*0xc*

解答:

在printf函数中输出的‘%’后跟上不同的特殊字符或数字,有着截然不同的输出效果,熟记并掌握,能让你的输出更加美观且符合所需规范。

空格    ‘ ’

在输出左边打印空格,如果是负数则用则用 ‘-’ 代替空格

数字   >0数字表示打印位数,如果需要打印的内容位数不够,则用  ‘ ’ 补齐至规定位数
数字   =0

在左边补零,常与前一种情况连用 ” %05d “ ,表示不用 ‘ ’ 补齐至规定位数,而是用0补齐

字符    ‘+’在输出左边补上正负号
字符     ‘-’输出左对齐
字符     ‘#’左边补上输出对应进制的前导,16进制对应” 0x “,八进制对应 ” 0 “

二、' -= ' 和 ' += ' 的由来

请问以下代码在屏幕上输出什么?

#include<stdio.h>

int main()
{
	int a = 0;
	a=-1;
    printf("%d", a);
	return 0;
}

答案:

-1

解答:

其实上面并不是我想问的真是问题,我想问大家的其实是: 为什么c语言中用 "a -=  1" 来表示 "a = a - 1",而不用"a =- 1"?

在一些老版c语言中其实是支持用 ’=-‘ 和 ’=+‘ 来代表现在’-=‘与’+=‘的含义的,只不过缺陷经过上面的例子你也发现了,”a =- 1“ 与 “a = -1”容易存在歧义,所以随着c语言的发展,自然只有不容易存在歧义的 ’-=‘ 和 ’+=‘ 留了下来。


三、函数原型与函数前置声明

请问一下函数声明1,和函数申明2,哪一个能成功让main函数调用sum?

#include<stdio.h>

int sum();               //1
int sum(int x, int y);   //2

int main()
{
	int x = 1;
	int y = 2;
	int z = 0;
	z = sum(x, y);
	printf("%d", z);
	return 0;
}


int sum(int x, int y)
{
	return x + y;
}

答案:

两者都能实现对sum函数的声明。

解答:

一些读者可能觉得只有第二个可以,其实两者都能做到对函数的声明,不过还是有一些区别。

不常见的1叫 函数声明 ,其结构为:函数返回类型    函数名()

int sum();

而我们平时大多数时候使用的2叫做 函数原型 ,其结构为:函数返回类型    函数名(形参列表)

int sum(int x, int y); 

不过第一种声明方式因为没有给出函数可接受的参数类型和个数,于是编译器无法对函数调用语句执行静态安全检查(即检查实参与形参的个数、类型及顺序等是否匹配)。这可能导致不正确的参数传递,从而导致运行时错误甚至破坏堆栈的情况,所以现在都是使用第二种函数原型进行函数声明(C99把旧的非原型形式视为过时,这意味着非原型形式以后可能被禁止)。


四、结构体位段

请问以下代码在屏幕上输出什么?

#include<stdio.h>

struct A
{
    int a : 2;
    int b : 5;
    int c : 10;
    int d : 30;
};

int main()
{
    printf("%d", sizeof(struct A));
    return 0;
}

答案:

8

解答:

1.位段的成员只能是int,unsigned interesting和signed int char类型(char和int不能混用)

2.位段的空间上是按照需要以四个字节(int)或者1个字节(char)的方式开辟的

3.位段设计很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

这里我们的位段使用了int类型,因此每次开辟四个字节

剩下17位,而d需要30位,显然四个字节已经不够用,于是在开辟四个字节存放d,所以最后的答案是8个字节。


 五、函数传递

请问以下代码在屏幕上输出什么?

#include<stdio.h>
#include<string.h>

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
int main()
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf("%s", str);
	return 0;
}

 答案:

程序崩溃或没有输出

解答:

因为GetMemory并不能传递动态内存,main函数中的str一直都是NULL,从而使得strcpy(str, "hello world");无法正常运行导致程序没有得到我们预期的结果。、


--复习题--

#include<stdio.h>
#include<string.h>

 struct A
{
    char a : 3;
    char b : 4;//1
    char c : 5;//2
    char d : 4;//4
};

int sum();

int main()
{
	int x = 3, y = 5, z = 0;
	z = sum(x, y);
	printf("*%+03d*\n",z);
	printf("*%- 5d*\n",  z);
	printf("%d", sizeof(struct A));
	return 0;
}

int sum(int x, int y)
{
	return x + y;
}

答案:

*+08*   
* 8   *  // '*' 内共五个字符位
3

答错了请再回去仔细看看哦!


总结

希望大家看了有所收获,总共5分,你得到了几分呢?如果你全部答对了,可以在评论区打出简单,以激励我写出更”难“的题来考验大家😘。

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值