C注意

int a[12]={"hello world"};

假设有一个数组int a[5],a[0]为数组的第一个元素,数组名a就是数组元素a[0]的地址,即对于一维数组 &a[0]==a,他们指向同样的一个内存单元。
对于一维数组而言,&a[0],a,&a都是指向同一个内存地址,虽然他们所指向的地址是相同的,但是他们本身的类型是不一样的,a[0]='h'是一个char类型的变量,&a[0]是一个char *类型的指针。对&a[0]进行加一操作会指向a[1]。但是a是一个数组变量,&a是一个char *[12]类型的指针,对&a进行+1操作会跳过12个char类型的地址。

对于二维数组而言:

char  str[][10] = {"hello","world","there"};
printf("0x%-10x",str); // 0
printf("0x%-10x",str[0]); // 0
printf("0x%-10x",str[1]); // 10
printf("0x%-10x",&str[0][0]); // 0
printf("0x%-10x",&str[0][0]+1); // 1
printf("0x%-10x",&str);  // 1 
printf("0x%-10x",&str +1); // 30 
// 像main()函数那样来传递字符串参数
void my_copy(char **s, int n)
{
  /*do anything*/
}

int main()
{
    char *str[] = {"hello","world","there"};
    my_copy( ( char *[] ){str[0],str[1],str[2],NULL});//C99
//or
    char *p[]={ str[0],str[1],str[2],NULL };//C89
    my_copy(p,3);
}

数组指针

数组指针是一个指向数组的指针变量,通常用来指向数组的首地址,也可以指向数组的元素。

为了编写将二维数组作为参数的函数,数组名被其视为地址,因此,相应的形式参数是一个指针,就像一维数组一样.例如有下面一段代码:

int data[3][4] = {{1,2,3,4}, {5,6,7,8},{1,2,3,5}};
int total = sum(data,3);

那么sum函数的原型应该是什么样子的呢?data是一个数组名,这个数组有3个元素.第一个元素本身是一个数组,由4个int值组成.因此data的类型是指向4个int组成的数组的指针.正确的原型如下:int sum(int (*ar2)[4],int size);还有另外的一种格式,这种格式与上述的原型含义一致,但是可读性更强int sum(int ar2[][4],int size);

  1. 要对绝对地址 0x100000赋值,我们可以使用*(unsigned int *)0x100000 = 1234;那么如果想让程序跳转到绝对地址0x100000去执行,那么应该怎么做?
    答: *((void(*)(void))0x100000)(void);首先要将0x100000强制转换成函数指针,即:(void(*)(void))0x100000然后再调用它:*(void(*)(void))0x100000(void); 或者使用一更加直观的方式:typedef void(*)(void) voidFuncPtr; *((voidFuncPtr)0x100000)(void);

  1. 分析下面这段程序
void getmemory(char *p)
{
  p=(char *)malloc(100);
  strcpy(p,"hello world");
}
int main()
{
  char *str = NULL;
  getmemory(str);
  printf("%s\n",str);
  free(str);
  return 0;
}

在这程序中存在一个最大的问题是getmemory()中的malloc并不能够返回动态内存,free对str的操作是很危险的,此时str仍然是指向NULL的,并不是malloc返回的地址。应该修改为二级指针,如下:

void getmemory(char **p)
{
  *p = (char *)malloc(100);
  strcpy(p,"hello world");
}

int main()
{
  char *str = NULL;
  getmemory(&str);
  printf ("%s\n",str);
  free(str);
  return 0;
}

  1. 分析下面这段程序
typedef struct AA
{
    int b1:5;
    int b2:2;
}AA

int main(int argc, char const *argv[])
{
    AA aa;
    char cc[100];
    strncpy(cc,"0123456789",10);
    memcpy(&aa,cc,sizeof(AA));
    printf("%d:%d\n",aa.b1,aa.b2);
    return 0;
}

解析:输出为 -16和1,首先sizeof(AA)的大小为4,b1和b2分别占据了5个bit和2个bit。经过strcpy和memcpy之后aa的4个字节所存放的值是0,1,2,3的ASCII码,即00110000,00110001,00110010,00110011,所以,最后一步:显式的是这4个字节的前5位和之后的2位,分别是:10000和01,因为int是由正负之分的,所以结果为-16和1。


  1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#define SECONDS_PER_YEAR 60 * 60 * 24 * 365UL 预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。由于这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。

  1. 编写一个标准的的宏MIN,将这个宏输入的两个参数返回较小的一个。
    #define MIN(A,B) do{(A)<=(B)?(A):(B)}while(0)

  1. 预处理器标识#error的作用是什么?
    #error命令是C/C++语言的预处理命令之一,当预处理器预处理到#error命令时将停止编译并输出用户自定义的错误消息。其目的就是保证程序是按照你所设想的那样进行编译的。例如:
    程序中往往有很多的预处理指令
#ifdef XXX
...
#else

#endif

当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:

#ifdef XXX
...
#error "XXX has been defined"

#else

#endif

这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。


7.c和c++中的struct有什么不同?
c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private


8 .用两个队列实现一个栈的功能
答:设两个栈分别为A,B, 一开始均为空。入队: 将新元素push入栈A; 出队: (1)判断栈B是否为空; (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出;这样实现的队列入队和出队的平摊复杂度都还是O(1)。所以的入栈操作都在A上进行,所有的出栈操作都在B上进行。


  1. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
    答案:c用宏定义,c++用inline;


  1. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。

__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。


  1. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
    #define dPS struct s *
    typedef struct s * tPS;
    以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
    dPS p1,p2;
    tPS p3,p4;
    第一个扩展为struct s * p1, p2;上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。

  1. *100 = 25; 它看上去像是把 25 赋值给了地址为100的内存单元,但是这条语句实际上是非法的,因为字面值 100 的类型是整型,而间接访问操作只能作用于指针类型表达式。如果你确实想把 25 存储于位置 100,你必须使用强制类型转换。*(int *)100 = 25;

  1. 浮点数和0比较时使用<0.000001(6个零)&&>-0.000001
  • c和c++对有效数位的要求是,float至少32位,double至少48位且不少于float,long double至少和double一样多(这里指的是二进制数)。通常来说,float为32位,double为64位,long double为80、96、128位。大多数情况下,编译器为float分配4字节,double则分配8字节。

  • float32位组成:最高位的1位为符号位,接着指数位共8位,指数范围-127 ~ +128(补码形式),然后尾数位共23位。那为什么float型计算机的显示结果只显示6位有效数字呢?那是因为,计算机内部以二进制法存储数据,尾数23即共 2^23 个有效数字,那么转化成十进制就是log10( 2^23 )=6.92,即6 ~ 7位有效数字,计算机保证至少6位有效数字的精度。同理,64位数的double1位符号位,11位指数位,指数范围为-1023 ~ +1024,52位尾数,有效数字为15 ~ 16,保证有效数字为15位精度。但是,我们会发现,无论用float还是double,我们用cout输出值最多显示6位有效数字。那是因为c++cout默认输出的精度是6位(四舍五入),如果想显示多于6位的精度,那么可以输入头文件#include <iomanip>,然后在输出语句之前插入cout << setprecision(x),x是要显示的精度。假如要显示的精度超出原来数字的实际精度,那么就会有超出部分的误差,例如:

float a =2.12351f;
cout << setprecision(10)<<a<<endl;//输出结果2.123509884

又如:

float a= 2.34E+22f;
float b = a+1.0f;
cout<<"a="<<a<<endl;//a=23400001102275227418424.000000
cout<<"b-a="<<b-a<<endl;//b-a=0.000000;改程序讲数字加1,然后减去原来的数字,结果应该为1,但是输出却是0;

从a的输出可以看出只有前7位是精确地,再往后就是110227...这些都是不精确的数字,因此从第七位往后不论加减都是没有意义的.
问题在于2.34e+22是一个小数点左边有23位的数字.再加上1,就是在第23位加1,但是float类型只能够表示数字中的前6位或者是7位,因此修改第23位对这个值不会有任何的影响.


  1. signed、unsigned关键字
    我们知道计算机底层只认识 0、 1.任何数据到了底层都会变计算转换成 0、 1.那负数怎么存储呢?肯定这个“-”号是无法存入内存的,怎么办?很好办,做个标记。把基本数据类型的最高位腾出来,用来存符号,同时约定如下:最高位如果是 1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号;如果最高位是 0,表明这个数是正数,其值为除最高位以外的剩余位的值。

  2. 在C/C++中,为了避免同一个文件被include多次,有两种方式:一种是#ifndef方式,一种是#pragma once方式(在头文件的最开始加入)。

#ifndef的是方式是受C/C++语言标准支持。#ifndef方式依赖于宏名不能冲突。它不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。缺点是如果不同头文件中的宏名不小心”碰撞”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况。由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,#ifndef会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式。

#pragma once一般由编译器提供保证:同一个文件不会被包含多次。这里所说的”同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。无法对一个头文件中的一段代码作#pragma once声明,而只能针对文件。此方式不会出现宏名碰撞引发的奇怪问题,大型项目的编译速度也因此提供了一些。缺点是如果某个头文件有多份拷贝,此方法不能保证它们不被重复包含。在C/C++中,#pragma once是一个非标准但是被广泛支持的方式。

#pragma once方式产生于#ifndef之后。#ifndef方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once方式有些编译器不支持(较老编译器不支持,如GCC 3.4版本之前不支持#pragma once),兼容性不够好。#ifndef可以针对一个文件中的部分代码,而#pragma once只能针对整个文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容