intfoo()// code for foo starts at memory address 0x002717f0{return5;}intmain(){foo();// jump to address 0x002717f0return0;}
在你的编程生涯中可能会犯这样的错误:
1 2 3 4 5 6 7 8 910111213
#include<iostream>intfoo()// code starts at memory address 0x002717f0{return5;}intmain(){std::cout<<foo<<'\n';// we meant to call foo(), but instead we're printing foo itself!return0;}
#include<iostream>intfoo()// code starts at memory address 0x002717f0{return5;}intmain(){std::cout<<reinterpret_cast<void*>(foo)<<'\n';// 告诉 C++ 将foo解析为空指针return0;}
intfoo(){return5;}intgoo(){return6;}intmain(){int(*fcnPtr)(){&foo};// fcnPtr points to function foofcnPtr=&goo;// fcnPtr now points to function gooreturn0;}
下面代码是一种常见的错误:
1
fcnPtr=goo();
该行代码将 goo() 的返回值(类型为int) 赋值给 fcnPtr (实际期望的类型是int(*)()),这并不是我们的本意。我们其实希望 fcnPtr被赋值为 goo 的地址,而不是 goo() 的 So no parentheses are needed.
注意,函数指针的类型(返回值和参数)必须和函数类型匹配,一些实例如下:
1 2 3 4 5 6 7 8 91011
// function prototypesintfoo();doublegoo();inthoo(intx);// function pointer assignmentsint(*fcnPtr1)(){&foo};// 对 int(*fcnPtr2)(){&goo};// 错 -- 返回值类型不正确double(*fcnPtr4)(){&goo};// 对 fcnPtr1=&hoo;// 错 -- fcnPtr1 不接受参数,和 hoo() 不匹配int(*fcnPtr3)(int){&hoo};// 对
intfoo(intx){returnx;}intmain(){int(*fcnPtr)(int){&foo};// Initialize fcnPtr with function foo(*fcnPtr)(5);// call function foo(5) through fcnPtr.return0;}
第二种方法是通过隐式解引用:
1 2 3 4 5 6 7 8 9101112
intfoo(intx){returnx;}intmain(){int(*fcnPtr)(int){&foo};// Initialize fcnPtr with function foofcnPtr(5);// call function foo(5) through fcnPtr.return0;}
intfoo(intx){returnx;}intmain(){int(*fcnPtr)(int){&foo};// Initialize fcnPtr with function fooif(fcnPtr)// make sure fcnPtr isn't a null pointerfcnPtr(5);// otherwise this will lead to undefined behaviorreturn0;}
#include<utility> // for std::swapvoidSelectionSort(int*array,intsize){// Step through each element of the arrayfor(intstartIndex{0};startIndex<(size-1);++startIndex){// smallestIndex is the index of the smallest element we've encountered so far.intsmallestIndex{startIndex};// Look for smallest element remaining in the array (starting at startIndex+1)for(intcurrentIndex{startIndex+1};currentIndex<size;++currentIndex){// If the current element is smaller than our previously found smallestif(array[smallestIndex]>array[currentIndex])// COMPARISON DONE HERE{// This is the new smallest number for this iterationsmallestIndex=currentIndex;}}// Swap our start element with our smallest elementstd::swap(array[startIndex],array[smallestIndex]);}}
boolascending(intx,inty){returnx>y;// swap if the first element is greater than the second}
使用 ascending() 函数修改后的排序算法如下:
1 2 3 4 5 6 7 8 910111213141516171819202122232425
#include<utility> // for std::swapvoidSelectionSort(int*array,intsize){// Step through each element of the arrayfor(intstartIndex{0};startIndex<(size-1);++startIndex){// smallestIndex is the index of the smallest element we've encountered so far.intsmallestIndex{startIndex};// Look for smallest element remaining in the array (starting at startIndex+1)for(intcurrentIndex{startIndex+1};currentIndex<size;++currentIndex){// If the current element is smaller than our previously found smallestif(ascending(array[smallestIndex],array[currentIndex]))// COMPARISON DONE HERE{// This is the new smallest number for this iterationsmallestIndex=currentIndex;}}// Swap our start element with our smallest elementstd::swap(array[startIndex],array[smallestIndex]);}}
#include<utility> // for std::swap#include<iostream>// Note our user-defined comparison is the third parametervoidselectionSort(int*array,intsize,bool(*comparisonFcn)(int,int)){// Step through each element of the arrayfor(intstartIndex{0};startIndex<(size-1);++startIndex){// bestIndex is the index of the smallest/largest element we've encountered so far.intbestIndex{startIndex};// Look for smallest/largest element remaining in the array (starting at startIndex+1)for(intcurrentIndex{startIndex+1};currentIndex<size;++currentIndex){// If the current element is smaller/larger than our previously found smallestif(comparisonFcn(array[bestIndex],array[currentIndex]))// COMPARISON DONE HERE{// This is the new smallest/largest number for this iterationbestIndex=currentIndex;}}// Swap our start element with our smallest/largest elementstd::swap(array[startIndex],array[bestIndex]);}}// Here is a comparison function that sorts in ascending order// (Note: it's exactly the same as the previous ascending() function)boolascending(intx,inty){returnx>y;// swap if the first element is greater than the second}// Here is a comparison function that sorts in descending orderbooldescending(intx,inty){returnx<y;// swap if the second element is greater than the first}// This function prints out the values in the arrayvoidprintArray(int*array,intsize){for(intindex{0};index<size;++index){std::cout<<array[index]<<' ';}std::cout<<'\n';}intmain(){intarray[9]{3,7,9,5,6,1,8,2,4};// Sort the array in descending order using the descending() functionselectionSort(array,9,descending);printArray(array,9);// Sort the array in ascending order using the ascending() functionselectionSort(array,9,ascending);printArray(array,9);return0;}
运行结果如下:
12
9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9
酷不酷?我们给了调用者控制选择排序如何工作的能力。
调用者甚至可以定义自己的“奇怪的”比较函数:
1 2 3 4 5 6 7 8 91011121314151617181920212223
boolevensFirst(intx,inty){// if x is even and y is odd, x goes first (no swap needed)if((x%2==0)&&!(y%2==0))returnfalse;// if x is odd and y is even, y goes first (swap needed)if(!(x%2==0)&&(y%2==0))returntrue;// otherwise sort in ascending orderreturnascending(x,y);}intmain(){intarray[9]{3,7,9,5,6,1,8,2,4};selectionSort(array,9,evensFirst);printArray(array,9);return0;}
#include<functional>boolvalidate(intx,inty,std::function<bool(int,int)>fcn);// std::function method that returns a bool and takes two int parameters
如你所见,返回值类型定义在尖括号中,参数类型则被定义在括号中。如果没有参数的话,括号可以留空。
使用 std::function 更新之前的例子:
1 2 3 4 5 6 7 8 9101112131415161718192021
#include<functional>#include<iostream>intfoo(){return5;}intgoo(){return6;}intmain(){std::function<int()>fcnPtr{&foo};// declare function pointer that returns an int and takes no parametersfcnPtr=&goo;// fcnPtr now points to function goostd::cout<<fcnPtr()<<'\n';// call the function just like normalreturn0;}
类型别名也可以帮助 std::function 提高可读性:
12
usingValidateFunctionRaw=bool(*)(int,int);// type alias to raw function pointerusingValidateFunction=std::function<bool(int,int)>;// type alias to std::function