1.字符串反转,比如输入abcd123,然后编程321dcba
#include<stdio.h>
#include<string.h>
int main(void)
{
char buf[10];
char t;
int len;
puts("enter a string:");
fgets(buf,sizeof(buf),stdin);
puts("before:");
puts(buf);
len=strlen(buf);
for(int i=0;i<len/2;i++)
{
t=buf[i];
buf[i]=buf[len-1-i];
buf[len-1-i]=t;
}
puts("after:");
puts(buf);
return 0;
}
注意:fgets(scanf函数不能接受空格,而fgets函数可以)函数第一个参数是缓冲区buf,第二个是buf-1的大小,因为我们还有一个“\0”要占最后一个字节。字符串反转大概思路就是:第一个字符串和最后一个字符串对调,第二个字符串和最后一个字符串对调,这样依次完成,因为我们最后一个字符是结束符,所以要在for循环里面-1;
2.define宏定义
#include<stdio.h>
#include<string.h>
#define M 5
#define N M+M
int main(void)
{
int k;
k=N*N*5; //M+M*M+M*5 5+25+25
printf("%12d\n",k);
return 0;
}
当时做错的原因:define N M+M ,M=5;我把M+M算出来,不能这样,是N替换M+M,只要遇到N就替换为M+M,而不是把M+M算出来为10;
3.++ i 是先加后赋值;i ++ 是先赋值后加;++i和i++都是分两步完成的
#include<stdio.h>
#include<string.h>
int main(void)
{
int m=5;
if(m++>5)
printf("%d\n",m);
else
printf("%d\n",--m);
return 0;
}
m++>5,是先赋值,也就是先在if里面判断,然后再++;判断m没有大于5,执行else,然后--m;--是先减,然后再赋值,m在上面++过了,变成了6,在下面是--m,然后再赋值,所以结果是5。如果是是m--,那么结果就是6,先赋值,再减。
4.指针和i++
#include<stdio.h>
#include<string.h>
int a[]={0,2,4,6,8};
int main(void)
{
int i;
int *p=a;
for(i=0;i<4;i++)a[i]=*p++;
printf("%d\n",a[2]);
return 0;
}
解释:*p++就相当于*(p++),p先与++结合,然后p++整体再与*结合。*p++解析:++先跟p结合,但是因为++后置的时候,本身含义就是先运算后加1(运算指的是整体与前面的*进行运算;加1指的是p+1),所以实际上*p++符号整体对外表现的值是*p的值,运算完成后p再加1;等同于:*p,p+=1;
(*p)++这个的意思是:先去处p里面的值赋值给人家,再把p里面的值+1;
5.
void foo(void) {
unsigned int a = 6;
int b = -20;
(a+b > 6) puts("> 6") : puts("<= 6")
}输出的是什么
unsigned 是无符号数。 b 是有符号数负数,无符号数和有符号数混合运算 要注意 你到底 想计算什么。默认,把有符号数内容 当成无符号数解释 计算。-20 就当 0xffffffec (4294967276).显然(a+b > 6) 成立。输出 > 6。
6.三目运算符也叫条件运算符
如果希望获得两个数中最大的一个,可以使用 if 语句,例如:
if(a>b){ max = a; }else{ max = b; }
不过,C语言提供了一种更加简单的方法,叫做条件运算符,语法格式为:
表达式1 ? 表达式2 : 表达式3
运算规则是这样的:如果表达式1的值为真,则以表达式2 的值作为整个条件表达式的值,否则以表达式3的值作为整个条件表达式的值。
上面的 if else 语句等价于:
max = (a>b) ? a : b; //a>b,就输出a,否则输出b
我们来看一道面试题
问题:写一个”标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
#define Min(a,b) ( ((a)>=(b)) ? (b) : (a) )
7.关键字const是什么含意?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
首先理解一下 const int *a 和int *const a,去掉int,变成 const *a, 这样理解const 修饰 *a,*a就是a所指的那个数字,就是那个数字不能被改变。这样就比较好理解int *const a,去掉int,const修饰a,a是指针(里面存的地址)也就是里面的地址不能不改变。前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
8.指针与指针相减
我们直接来看这道题,老爱忘记。
#include<stdio.h>
int main(void)
{
int *p1,*p2,a[10];
p1=a;
p2=&a[5];
printf("%d\n",p2-p1);
return 0;
}
解析:任何编译器上都是5。指针减法含义:两个地址之间有多少个计量单位,那么p2-p1的意思就是p2和p1之间有多少个int,那么不管in是16位,还是32位,甚至是64位,和int的长度没有关系。
9.中断问题
中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断,从而产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
答: a、ISR不能返回一个值。
b、ISR不能传递参数。
c、在许多处理器编译器中,浮点一般都是不可冲入的。有些处理器编译器需要让额外的寄存器入栈,有些处理器编译器就不允许在ISR中做浮点运算。此外ISR应该是短而有效率的。在ISR中做浮点运算是不明智的。
d、printf经常是有冲入性和性能上的问题,所以一般不使用printf函数
10.++前置++后置
#include<stdio.h>
int main(int argc, char *argv)
{
int a = 1, b = 1;
int aplus, bplus;
aplus = a++; //先把a的值赋值给aplus,a再加1
bplus = ++b; //b的值先加1, 再把值赋值给bplus
printf("a aplus b bplus\n");
printf("%d %d %d %d\n", a, aplus, b , bplus);
return 0;
}
程序运行如下:
a aplus b bplus
2 1 2 2
#include<stdio.h>
#define TEN 10
int main(int argc, char *argv)
{
int n = 0;
while (n++ < TEN)
printf("%5d",n);
printf("\n");
return 0;
}
程序运行如下:
1 2 3 4 5 6 7 8 9 10
分析 :这里是先比较大小再加1, n一开始为0,0小于10,n+1,输入1,一直加到9小于10,9+1,所以输出10
#include<stdio.h>
#define TEN 10
int main(int argc, char *argv)
{
int n = 0;
while (++n < TEN)
printf("%5d",n);
printf("\n");
return 0;
}
程序运行如下:
1 2 3 4 5 6 7 8 9
分析:这里是先比较大小,再+1,相当于n = n+1;
11.指针偏移量的问题
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5};
int *p = (int *)(&a + 1);
printf("%d %d \n", *(p - 1), *p - 1);
printf("%ld %ld\n", sizeof(a), sizeof(&a));
return 0;
}
12.指针指向常量区
str1和st2的地址是不是一样的,结果是一样的为什么呢?
#include <stdio.h>
int main()
{
char *str1 = "hello world";
char *str2 = "hello world";
printf("%p\n", str1);
printf("%p\n", str2);
char *str3 = str2;
str3 = "NICE";
printf("%s\n", str3);
printf("%s\n", str2);
return 0;
}
13.函数返回值一样吗?第二个会发生段错误
#include <stdio.h>
char* get_hello1();
char* get_hello2();
int main()
{
printf("%s\n",get_hello1());
printf("%s\n",get_hello2());
return 0;
}
char *get_hello1()
{
char *str1 = "hello";
return str1;
}
char *get_hello2()
{
char str2[] = "hello";
return str2;
}
14.指针的偏移量
#include<stdio.h>
int main(int argc, char *argv[])
{
int a[] = {384, 385, 386};
char *p = (char *)a;
printf("%d\n", *p);
printf("%d\n", *(p + 1));
printf("%d\n", *(p + 4));
return 0;
}
简单分析一下:大概意思就是4个字节,转换成1个字节。384的二进制是1 1000 0000,只取低8位就是1000 0000,也就是-128,*(p+1)就是指针移动1个字节,也就是到1的地方,结果就是1。
运行结果如下:
-128
1
-127
15.一道很不错的题目,对于复习大小端,和内存分布,指针偏移很有帮助。
#include<stdio.h>
/* 小端模式 */
int main(int argc, char *argv)
{
int a[4] = {1, 2 ,3, 4};
int *p1 = (int *)(&a + 1);
int *p2 = (int *)((char *)&a + 1);
printf("0x%x, 0x%x\n", *(p1-1), *p2);
return 0;
}
先复习一下知识点,有点忘记了
a+1:就是数组首地址加上一个元素所占的地址大小,这里int是4个字节,所以加上1x4.
&a+1:代表的是加上整个数组的大小,这里数组尺寸是4,所以+1代表的是地址加上4x4.为了更好理解,画内存图来分析理解
结果是0x4和0x2000000,0x2000000有点想不明白,看了“int *类型指针变量强制转换为char *的结果”,的博客就明白了,博客地址:
(85条消息) int *类型指针变量强制转换为char *的结果_肘子君的博客-CSDN博客_int指针强制转换成char指针
假如有这么一个程序
int a = 0x44332211;
int *p1 = &a;
char *p2 = (char *)&a;
printf("*p1 = 0x%x\n",*p1);
printf("*p2 = 0x%x\n",*p2);
结果如下图
分析:
a,p1,p2在内存中的实际效果如下(地址是假设的)
p1和p2所指向的都是变量a的地址。
不同的地方在解指针的时候。
p1在解指针时,将0x00当作是四个字节的内存空间大小的首地址。然后以int的解析类型进行解析。也就是说在解指针时会将从0x00为起始的后面总共四个地址所包含的内存空间的数都以int的解析类型解析出来。
p2在解指针时,将0x00当作是一个字节的内存空间大小的首地址。然后以char的解析类型进行解析。也就是说在解指针时会将从0x00为起始的后面总共一个地址所包含的内存空间的数都以char的解析类型解析出来。
0x44332211在变量a指向的内存空间中的分布。
*p1取a中的值时:四个字节作为整体一起解指针
*p2取a中的值时:对一个字节的空间大小进行解指针
由于p1和p2的指针类型不同。所以在对p1和p2做+1操作时,效果也会不同。
p1+1后,p1+1指向的内存地址为0x00+4=0x04;
p2+1后,p2+1指向的内存地址为0x00+1=0x01;
16.字符串大写字母转小写字母,代码比较简单,忘记的话就需要看一下ascii码
#include<stdio.h>
#include<string.h>
int main()
{
int i, len;
char s[101] = {0};
gets(s);
len = strlen(s);
//大写变小写
for(i = 0; i < len; i++) {
if(s[i] >= 'A' && s[i] <= 'Z') {
s[i] = s[i] + 32; /* 不明白就看一下ASCII码 */
}
}
puts(s);
return 0;
}
17.联合体(也叫共用体)就是所有成员共用一块空间,空间大小取决于最大成员的大小。这里是抖音看到的一道笔试题,是联合体里面的成员变量相加。还做错了。算成了3,想着被第三个成员占用了,就想当然的认为是0;
#include <stdio.h>
typedef union {
int a;
int b;
struct {
int c;
} d;
} new_type;
int main(void)
{
new_type dat;
dat.a = 1;
dat.b = 2;
dat.d.c = 3;
printf("%d\n", dat.a + dat.b + dat.d.c);
return 0;
}
运行结果: