因为从二进制的角度讲,n相当于在n - 1的最低位加上1。举个例子,8(1000)= 7(0111)+ 1(0001),所以8 & 7 = (1000)&(0111)= 0(0000),清除了8最右边的1(其实就是最高位的1,因为8的二进制中只有一个1)。再比如7(0111)= 6(0110)+ 1(0001),所以7 & 6 = (0111)&(0110)= 6(0110),清除了7的二进制表示中最右边的1(也就是最低位的1)。
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
/*求二进制数中1的个数*/
int BitCount2(unsigned int n)
{
unsigned int i =0 ;
for(i = 0; i < n; i++)
{
n &= (n - 1) ; // 清除最低位的1
}
return i ;
}
int main(int argc, char *argv[])
{
printf("%d\n", BitCount2(9));
return 0;
}
------------------------------------
drwxrwxr-x 3 ljq ljq 4096 Dec 14 10:19 ..
drwxrwxr-x 8 ljq ljq 4096 Dec 14 11:14 .git
-rwxrwxr-x 1 ljq ljq 7408 Dec 14 11:29 main
-rw-rw-r-- 1 ljq ljq 621 Dec 14 11:29 main.c
-rw-rw-r-- 1 ljq ljq 2450 Dec 14 10:23 main.tar.gz
后面9位分为3组,每3组作为1组,从左到右分别表示 文件属主, 文件属组,和 其他所有用户的权限。
d:此文件是个实实在在的文件而非一个目录(目录也被认为是文件)
r--:同群组用户对此文件有读权限,没有用写、执行的权限。
r-x:其它用户对此文件有读、执行的权限,没有写权限。
八进制的语法使用数字表示各个权限分别是r(4)、w(2)、x(1)、-(0)。在本问题中属主权限位是rw-,转换为八进制为4+2+0=6,属组权限位r--转换为八进制为4+0+0=4。其他人权限位r--转换为八进制为4+0+0=4。将三个权限位表示起来是644。
ps是linux下最常用的也是非常强大的进程查看命令。
ps -ef
-e 显示所有进程。
-f 全格式。
A.2和2 B.2和5 C.5和2 D.5和5
u-boot系统启动流程 大多数bootloader都分为stage1和stage2两部分,u-boot也不例外。
依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
1、Stage1 start.S代码结构 u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下
(1) 定义入口。:
该工作通过修改连接器脚本来完成。
(2)设置异常向量(Exception Vector)。
(3)设置CPU的速度、时钟频率及终端控制寄存器。
(4)初始化内存控制器。
(5)将ROM中的程序复制到RAM中。
(6)初始化堆栈。
(7)转到RAM中执行,该工作可使用指令ldr pc来完成。
2、Stage2
C语言代码部分 lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作:
(1)调用一系列的初始化函数。
(2)初始化Flash设备。
(3)初始化系统内存分配函数。
(4)如果目标系统拥有NAND设备,则初始化NAND设备。
(5)如果目标系统有显示设备,则初始化该类设备。
(6)初始化相关网络设备,填写IP、MAC地址等。
(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
volatile变量的几个例子:
并行设备的硬件寄存器(如状态寄存器);
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables);
多线程应用中被几个任务共享的变量。
int *p;
p=(int*)0x67a9;
*p=0xaa66
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
sizeof (str ) = ____
sizeof ( p ) = _____
sizeof ( n ) = _____
void Func ( char str[100])
{
// 请计算
sizeof( str ) = _____
}
9、 请计算sizeof的值:
void *p = malloc( 100 );
// 请计算
sizeof ( p ) = ______
用尖括号表示先在系统目录查找。
A 在同一时刻 B 一定在不同时刻 C 在某一时间间隔 D 依次在不同时间间隔内
主函数:①输入任意10个正整数给数组;②调用SUB1对数组进行排序;③从键盘输入一个正整数,调用SUB2将其插入该数组。
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 void bubble_sort(int inputPara[], int len)
5 {
6 int i, j;
7 for (i = 0; i < len; i++)
8 {
9 for (j = len -1; j >= i; j--)
10 {
11 if (inputPara[j-1] > inputPara[j])
12 {
13 inputPara[j-1] ^= inputPara[j];
14 inputPara[j] ^= inputPara[j-1];
15 inputPara[j-1] ^= inputPara[j];
16 }
17 }
18 }
19 }
20
21 int main()
22 {
23 int iarray[1024] = {9, 5, 4 ,7, 8, 2, 1, 1};
24 bubble_sort(iarray, 8);
25 int i = 0;
26 for (i = 0; i < 8; i++)
27 {
28 printf("%d ", *(iarray + i));
29 }
30 return 0;
31 }
数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间
共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
linux常用的进程间的通讯方式
(1)、管道(pipe):管道可用于具有亲缘关系的进程间的通信,是一种半双工的方式,数据只能单向流动,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
(2)、命名管道(named pipe):命名管道克服了管道没有名字的限制,同时除了具有管道的功能外(也是半双工),它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3)、信号(signal):信号是比较复杂的通信方式,用于通知接收进程有某种事件发生了,除了进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
(4)、消息队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺。
(5)、共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6)、内存映射:内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
(7)、信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
(8)、套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
没有操作系统的情况下,一个程序一直独占着全都cpu。
如果要有两个任务来共享同一个CPU,程序员就需要仔细地为程序安排好运行计划--某时刻cpu和由程序A来独享,下一时刻cpu由程序B来独享。
而这种安排计划后来成为OS的核心组件,被单独名命为“scheduler”,即“ 调度器”,它关心的只是怎样把单个cpu的运行拆分成一段一段的“运行片”,轮流分给不同的程序去使用,而在宏观上,因为分配切换的速度极快,就制造出多程序并行在一个cpu上的假象。
2、在单核计算机里,有一个资源可以被多个程序共用,然而会引出麻烦:内存。
在一个只有调度器,没有内存管理组件的操作系统上,程序员需要手工为每个程序安排运行的空间 -- 程序A使用物理地址0x00-0xff,程序B使用物理地址0x100-0x1ff,等等。
然而这样做有个很大的问题:每个程序都要协调商量好怎样使用同一个内存上的不同空间,软件系统和硬件系统千差万别,使这种定制的方案没有可行性。
为了解决这个麻烦,计算机系统引入了“虚拟地址”的概念,从三方面入手来做:
2.1、 硬件上,CPU增加了一个专门的模块叫 MMU,负责转换虚拟地址和物理地址。
2.2、 操作系统上,操作系统增加了另一个核心组件: memory management,即内存管理模块,它管理物理内存、虚拟内存相关的一系列事务。
2.3、 应用程序上,发明了一个叫做【进程】的模型,(注意)每个进程都用【完全一样的】虚拟地址空间,然而经由操作系统和硬件MMU协作,映射到不同的物理地址空间上。 不同的【进程】,都有各自独立的物理内存空间,不用一些特殊手段,是无法访问别的进程的物理内存的。
3、现在,不同的应用程序,可以不关心底层的物理内存分配,也不关心CPU的协调共享了。然而还有一个问题存在:有一些程序,想要共享CPU,【并且还要共享同样的物理内存】,这时候,一个叫【线程】的模型就出现了,它们 被包裹在进程里面,在调度器的管理下共享CPU,拥有同样的虚拟地址空间,同时也共享同一个物理地址空间,然而,它们无法越过包裹自己的进程,去访问别一个进程的物理地址空间。
4、进程之间怎样共享同一个物理地址空间呢?不同的系统方法各异,符合posix规范的操作系统都提供了一个接口,叫 mmap,可以把一个物理地址空间映射到不同的进程中,由不同的进程来共享。
5、PS:在有的操作系统里, 进程不是调度单位(即不能被调度器使用),线程是最基本的调度单位,调度器只调度线程,不调度进程,比如VxWorks
int binSearch(int key,int array[], int length)
{
int mid=0;
int start = 0;
int end = length - 1;
while (start <= end) {
mid = (end - start) / 2 + start;
if (key == array[mid]) {
return mid;
}
if (key < array[mid]) {
end = mid - 1;
} else if (key > array[mid]) {
start = mid + 1;
} else {
return mid;
}
}
return -1;
}
node *inverselinklist(node *head)
{
node *p1,*p2,*p3;
if(NULL==head||NULL==head->next) {
return head;
}
p1=head;
p2=p1->next;
while (p2) {
p3=p2->next;
p2->next=p1;
p1=p2;
p2=p3;
}
head->next=NULL;
head=p1;
return head;
}
#include <stdio.h>
void main(){
int arr[]={6,7,8,9,10};
int *ptr=arr;
*(ptr++)+=123;
printf("%d,%d",*ptr,*(++ptr));
}
输出(8,8)
char * strcpy(char *dst,const char *src)
{
assert(dst != NULL && src != NULL);
char *ret = dst;
while ((*(dst++) = *(src++)) != '\0') NULL;
return (char *)ret;
}
char *strcat(char *strDest, const char *strSrc)
{
char *address = strDest;
assert((strDest != NULL) && (strSrc != NULL));
while(*strDest != '\0' )
strDest++;
while((*strDest++ = *strSrc++) != '\0');
return address;//为了实现链式操作,将目的地址返回
}
int strlen(const char *str)
{
int len = 0;
assert(str != NULL);
while(*str++ != '\0')
len++;
return len;
}
int strcmp(const char *src, const char *dst)
{
int ret = 0 ;
assert((dst != NULL) && (src != NULL));
while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
{
++src;
++dst;
}
if(ret < 0)
ret = -1;
else if(ret > 0)
ret = 1;
return(ret);
}
/*关于指针的理解char *const *(*next)();
*next是个函数指针。
*该函数的参数为空(任意),返回值类型是个二级指针char *const *,即:指向char型的指针的const指针。
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
char * const *func(char * const *x)
{
return x;
}
void main()
{
char * const*(*f)(char * const *x);/* 声明f一个函数指针,函数的参数为指向char类型的指针的const指针*/
f = func;
}
总结指针函数与函数指针最简单的辨别方式:
{
p = (char *)malloc(100);
}
void Test( void )
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world" );
printf(str);
}
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void GetMemory(char **p)
{
//新开辟的100个字节的内存空间首地址赋给*p,*p即str,
*p = (char *)malloc(100 * sizeof(char));
}
void Test(void)
{
char *str = NULL;
GetMemory(&str);
strcpy(str, "hello world" );
printf(str);
if(str != NULL)
{
free(str);
str = NULL;
}
}
void main()
{
Test();
system("pause");
}
拓展:
博客园
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <assert.h>
//将源字符串加const,表明其为输入参数
char *MyStrcat(char *strDest, const char *strSrc)
{
char *address = strDest;
assert((strDest != NULL) && (strSrc != NULL));//对源地址和目的地址加非0断言
while(*strDest != '\0' )
//*strDest最后指向该字符串的结束标志’\0’。
strDest++;
while((*strDest++ = *strSrc++) != '\0');
return address;//为了实现链式操作,将目的地址返回
}
void Test()
{
char a[1024]= "markyuan";
char b[6]= "yyyyy";
char *cat = MyStrcat(a,b);
printf("%s\n",cat);
}
void main()
{
Test();
system("pause");
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>
char *my_strrev(char *str)
{
char *end = str;
char *start = str;
while(*end != '\0')
end++;
end--;;
while (start < end)
{
*start ^= *end;
*end ^= *start;
*start ^= *end;
start++;
end--;
}
return(str);
}
void main(){
char a[] = "aBcDeF";
printf("%s\n", my_strrev(a));
}
压缩规则:
2. 压缩字段的格式为"字符重复的次数+字符"。例如:字符串"xxxyyyyyyz"压缩后就成为"3x6yz"
要求实现函数:
void stringZip(const char *pInputStr, long lInputLen, char *pOutputStr);
【输入】 pInputStr: 输入字符串
lInputLen: 输入字符串长度
【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长;
【注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int stringZip(const char *strSrc, long len, char *strDest)
{
if(strSrc == NULL || len == 0 || strDest == NULL || len > 99)
return 1;
int countOfPerChar=0;
for(int i = 0; i < len; i++)
{
if(strSrc[i] == strSrc[i+1])
countOfPerChar++;
else
{
countOfPerChar++;
if(countOfPerChar == 1)
{
*strDest++ = strSrc[i];
}
else if(countOfPerChar <= 9)
{
*strDest++ = strSrc[i];
*strDest++ = (char)(countOfPerChar + '0');//把数字1转换成字符‘1’
}
else if(countOfPerChar <= 99)
{
*strDest++ = strSrc[i];
*strDest++ = (char)(countOfPerChar/10 + '0');
*strDest++ = (char)(countOfPerChar%10 + '0');
}
countOfPerChar = 0;//统计完同一字符置为0
}
}
*strDest++='\0';
return 0;
}
void main()
{
char *str = "111AAKKKKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
int len = strlen(str);
char * outstr = (char *)malloc((len + 1) * sizeof(char));
stringZip(str,len,outstr);
printf("%s\n",outstr);
free(outstr);
outstr = NULL;
system("pause");
}
------------------------------------
1.栈-有编译器自动分配释放
2.堆-一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,data段,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,bss段。-程序结束释放
4.另外还有一个专门放常量的地方。-程序结束释放
二.在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区、常量存储区。
1.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程>序结束后,操作系统会自动回收。
3.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
4.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
5.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)
所以静态变量和全局变量放在全局/静态存储区,而常量存放在常量存储区,程序代码当然放在代码区了
内核虚拟存储器
----------------------
用户栈(Statk)
---------------------
堆(Heap)
----------------------
未初始化(BSS)
----------------------
初始化(Data)
----------------------
正文段(Text)
----------------------
.text段是代码段。它用来放程序代码(code)。它通常是只读的。
.data段是数据段。它用来存放初始化了的(initailized)全局变量(global)和初始化了的静态变量(static)。它是可读可写的。
.bss段是全局变量数据段。它用来存放未初始化的(uninitailized)全局变量(global)和未初始化的静态变量(static)。它也是可读可写的。bss是英文BlockStartedbySymbol的缩写。之所以把bss跟data分开来,是因为系统会为这些bss段的变量的初值清零。
.constdata段是常量数据段。它用来存放常量(const)。它也是只读的。
源程序中使用malloc分配的内存就是bss这一块,它的大小不是根据data的大小确定的,主要是由程序中同时分配内存最大值所确定的,不过如果超出了范围,也就是分配失败,可以等空间释放之后再分配。
1、只读的代码段称为Code段,即上述的.text段。
2、只读的常量数据段,被称作RO Data段,即上述的.constdata段。
以上两个段统称为RO段(Read Only),放在ROM或FLASH等非易失性器件中。
3、可读可写的初始化了的全局变量和静态变量段,被称作RW Data段(ReadWrite),即上述的.bss段。
4、可读可写的未初始化的全局变量和静态变量段,被称作ZI Data段(Zero Init),即上述的.data段。因为这个段里的变量要被初始化为零,所以叫ZI段。
以上两个段统称为RW段,而在运行时,它必须重新装载到可读可写的RAM中。
//在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。
#include <stdio.h>
#include <iostream>
using namespace std;
char firstNotRepeatingChar(char* pString, int lenth)
{
if(pString == NULL ||lenth == 0 )
return 1;
const int tableSize = 256;
int hashTable[tableSize];
for(int i = 0; i < tableSize; i++)
hashTable[i] = 0;
char *pHashKey = pString;
//for(int i = 0; i < lenth; i++)
while(*(pHashKey) != '\0')
hashTable[*(pHashKey++)]++;
pHashKey = pString;
//for(int i = 0; i < lenth; i++)
while(*pHashKey != '\0')
{
if(hashTable[*pHashKey] == 1)//首次仅有一次,返回该字符
return *pHashKey;
pHashKey++;
}
return 0;
}
int main()
{
char * strSrc = "abaccdeff";//"b";
cout<<strSrc<<endl;
char output = firstNotRepeatingChar(strSrc,strlen(strSrc));
cout<<output<<endl;
system("pause");
return 0;
}
/* 字符串中完成过滤重复字符的功能,
【输入】:1.常字符串;2.字符串长度;3.【out】用于输出过滤后的字符串.
【输出】:过滤后的字符串。
*/
#include <stdio.h>
#include <iostream>
using namespace std;
int stringFilterFast(const char *pInputStr, long lInputLen, char *pOutputStr)
{
//边界处理
if(pInputStr == NULL || pOutputStr ==NULL || lInputLen ==0)
return 1;
//变量初始化
char rstChar = '\0';
bool bNotRepeatFound = false;
const unsigned int size = 256;
unsigned int hashTable[size];//用于作为哈希表的数组
const char* pHashKey = pInputStr;
int outPutCnt = 0;
//初始化哈希表
for(unsigned int i = 0; i < size; i++)
hashTable[i] = 0;
//将pString读入到哈希表中
while(*pHashKey != '\0')
{
cout<<*pHashKey;
hashTable[*pHashKey++]++;//统计计数
//hashTable[*pHashKey]++;/
//pHashKey++;
}
cout<<endl;
//读取哈希表,对只出现1次的进行存储,对出现多次的进行1次存储。
pHashKey = pInputStr;
while(*pHashKey != '\0')
{
if(1 == (hashTable[*(pHashKey)]))//仅有一次
{
pOutputStr[outPutCnt++] = *pHashKey;
}
else if((hashTable[*(pHashKey)]) > 1) //若大于一次,统计第一次,然后对应的哈希统计值置为0
{
pOutputStr[outPutCnt++] = *pHashKey;
hashTable[*(pHashKey)] = 0;
}
pHashKey++;
}
pOutputStr[outPutCnt]= '\0';
return 0;
}
int main()
{
const char* strSrc = "desdefedeffdsswwwwwwwwwwdd";//"desfw";
char *strRst = new char[strlen(strSrc)+1];
int result = stringFilterFast(strSrc,strlen(strSrc), strRst);
cout<<strRst<<endl;
if(strRst != NULL)
{
delete []strRst;
strRst = NULL;
}
system("pause");
return 0;
}
1、什么是预编译?为什么要预编译?
答:预编译又称为预处理,是做些代码文本的替换工作。
处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等。
2、预编译、编译、链接的过程是怎么样的?
参考:http://blog.csdn.net/eastonwoo/article/details/8655243
第一步,预编译,将程序中的宏定义等预编译;
第二步,编译,将*.h,*.c等文件编译成为*.o文件;
第三步,汇编;
第四步,连接,将*.o文件连接库,生成可执行文件。
3、查找如下代码有什么问题?有什么值得改进的地方?
int a[60][250][1000],i,j,k,total;
for(i=0;i<=1000;i++)
for(j=0;j<=250;j++)
for(k=0;k<=60;k++)
total +=a[i][j][k];
答:
1、最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数;
2、各种变量应初始化;
3、total为int类型,长度可能不够;
4、三重for循环改为一个for如循环,实现累加功能。
扩展:
在32位的系统上short 的内存大小是2 个byte;
int 的内存大小是4 个byte;
long 的内存大小是4 个byte;
float 的内存大小是4 个byte;
double 的内存大小是8 个byte;
char 的内存大小是1 个byte。
可能不同的平台还会有所不同,具体平台可以用sizeof关键字测试一下。
4、查找错误。实现fun1函数去3次或3以上调用func2函数?
int a=0;
void fun1()
{
const int b =0
while(a<10);
b++;
while(b>2)
func2();
}
void func2()
{
...
}
void interrupt()
{
a++;
}
程序的本意是希望interrupt中断超过20次,fun1函数去调用func2函数。但是,由于编译器判断在fun1函数里面没有修改过i,因此可能只执行一次对从a到某寄存器的读操作,然后每次while判断都只使用这个寄存器里面的“a副本”,导致后边永远也不会被调用。如果变量加上static(全局)和volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。
void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
解析:*(a+1)其实很简单就是指a[1],输出为2.
&a+1如何理解?它不是首地址+1,系统会认为加了一个a类型相同数组,偏移了整个数组a的大小(也就是5个int的大小)。所以int *ptr=(int *)(&a+1);其实ptr实际是&(a[5]),也就是a+5.
&a是数组指针,其类型为int(*)[5];
而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同,a是长度为5的int数组指针,所以要加5*sizeof(int),所以ptr实际是a[5],但是ptr与(&a+1)类型是不一样的,这点非常重要,所以ptr-1只会减去sizeof(int*),a,&a的地址是一样的,但意思就不一样了,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]。
#include <stdio.h>
int a[4] = {1,2,3,4};
int main(){
printf("a = %p\n", a); // I
printf("&a = %p\n", &a); // II
printf("a + 1 = %p\n", a + 1);// III
printf("&a + 1 = %p\n", &a + 1);// IV
int *ptr= (int *)(&a + 1);
printf("*(ptr-1) = %p\n", *(ptr-1));// V
return 0;
}
vs2008输出:

6、在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
解决名字匹配问题,实现C++与C的混合编程。
#include<iostream>
#include<stdlib.h>
#include<string>
using namespace std;
void bubble_sort(int inputPara[], int len)
{
int temp;
for (int i = 0; i < len -1; i++)
{
for (int j = i + 1; j < len; j++)
{
if (inputPara[i] > inputPara[j])
{
temp = inputPara[i];
inputPara[i] = inputPara[j];
inputPara[j] = temp;
}
}
}
}
void main(int argc,char * argv[])
{
int x[] = { 6, 2, 4, 1, 5, 9 };
bubble_sort(x,6);
return;
}
void bubble_sort(int inputPara[], int len)
{
for (int i = 0; i < len; i++)
{
for (int j = len -1; j >= i; j--)
{
if (inputPara[j-1] > inputPara[j])
{
inputPara[j-1] ^= inputPara[j];
inputPara[j] ^= inputPara[j-1];
inputPara[j-1] ^= inputPara[j];
}
}
}
}
void bubble_sort(int inputPara[], int len)
{
bool flag = true;
for (int i = 0; i < len && true; i++)
{
for (int j = len -1; j >= i; j--)
{
flag = false;
if (inputPara[j-1] > inputPara[j])
{
inputPara[j-1] ^= inputPara[j];
inputPara[j] ^= inputPara[j-1];
inputPara[j-1] ^= inputPara[j];
flag = true;
}
}
}
}
//输入字符串,按照ascii值到字符‘U’的绝对值大小进行升序排列,如果绝对值相等,则按照原序排列。
#include<iostream>
#include "stdlib.h"
using namespace std;
int upSort(char *in, int len, char *out)
{
if(in == NULL) return 1;
if(out == NULL) return 2;
if(len == 0) return 3;
if(len > 1024) return 4;
char temp, tempCount;
char count[1024] = {0};
for(int i = 0; i < len; i++)
{
if(in[i] < 'U')
{
count[i] = 'U' - in[i];
}
else
{
count[i] = in[i] - 'U';
}
}
count[len] = '\0';
for(int i = 0; i < len -1; i++)
for(int j = i + 1; j < len; j++)
{
if(count[i] > count[j])
{
tempCount = count[i];
count[i] = count[j];
count[j] = tempCount;
temp = in[i];
in[i] = in[j];
in[j] = temp;
}
}
strcpy(out, in);
return 0;
}
int main(int argc, char* argv[])
{
int flag = 0;
int length;
char s[1024];
char t[1024];
cin>>s;
length = strlen(s);
flag = upSort(s, length, t);
if(0 == flag)
cout<<t<<endl;
else
cout<<"请检查输入的正确性!"<<endl;
system("pause");
return 0;
}
输出 3
比如字符串“abacacde”过滤结果为“abcde”。
要求实现函数:
void stringFilter(const char *pInputStr, long lInputLen, char *pOutputStr);
输入】 pInputStr: 输入字符串 lInputLen: 输入字符串长度
输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长;
输入:“deefd” 输出:“def”
输入:“afafafaf” 输出:“af”
输入:“pppppppp” 输出:“p”
/* main函数已经隐藏,这里保留给用户的测试入口,在这里测试你的实现函数,可以调用printf打印输出*/
/* 当前你可以使用其他方法测试,只要保证最终程序能正确执行即可 */
#include <stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<iostream>
using namespace std;
void stringFilter(const char *p_str, long len, char *p_outstr)
{
if(p_str == NULL || p_outstr == NULL)//输入参数有效性判断
{
p_outstr = NULL;
return;
}
int count[26] = {0};//计数器
char tmp;
int j = 0;
for(int i = 0;i < len; i++)
{
tmp = p_str[i] - 'a';
if(count[tmp] == 0)
{
count[tmp]++;
//p_outstr[j++] = p_str[i];
p_outstr[j] = p_str[i];
j++;
}
}
p_outstr[j] = '\0';
}
void main()
{
char inputStr[1024];
int len;
cout<<"请输入小写字母a-z,字符串长度限定在1024范围内"<<endl;
cin>>inputStr;
len = strlen(inputStr);
if(len > 1024)
cout<<"输入字符串太长,请限定在1024范围内"<<endl;
//分配内存
char *outStr = (char *)malloc(len * sizeof(char));//分配内存
stringFilter(inputStr, len, outStr);
printf("%s", outStr);
//释放申请的内存,并将指针置为空。
free(outStr);
outStr = NULL;
system("pause");