二维数组做参数

2014年5月14日 16:44

 

二维数组做函数参数。首先说下函数的声明。

一、正确的声明方法:

1.int function( int **array, int rows, int columns ); // func( (int**)array,  2,  5 ); 

2.int function( int array[3][5] ); // func( array );

3.int function( int array[][5] ); // func( array );

4.int function( int (*array)[5] ); // func( array );

注意:二维和高维不缺省

二、错误的声明方法:

1.int function( int array[][] );

2.int function( int array[3][] );

3.int function( int *array[5] );

三、当二维或多维数组做参数时,统统可以转化为一维数组做参数的情形。

Ex:

1.int function( int *a, int rows, int columns ); // func( (int*)array,  2,  5 );

2.int function( int a[], int rows, int columns ); // func( (int*)array, 2,  5 );

当访问数组内容的时候,可以按照数组在内存中的存储规则访问(按行依次存储)。如当为二维数组 int array[3][5],要访问 array[2][3] 时,可以写为 a[ 2*5 + 3 ];当为三维数组 int array[3][5][6],要访问 array[1][2][2] 时,可以写为 a[ 1*5*6 + 2*6 + 2] 。

四、实参的传入

函数声明的方法不同,对应传参方法也会大相径庭。

数组声明为 int a[][5] = {1,2,3,4,5,6,7,8,9,0};

函数调用实现见上//后内容。

五、总结

如果我们省略了数组的第二维或者更高维的大小,编译器将不知道如何正确的寻址。但是我们在编写程序的时候往往需要用到各个维数

都不固定的二维数组作为参数,该如何办呢?这时我们可以不把它当作一个二维数组,而是把它当作一个一维数组的普通指针,再另外

加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我

们可以把维数固定的参数变为维数随机的参数。在转变后的函数中,array[i][j] 这样的式子是非法的,因为编译器不能正确的为它寻址,

所以我们需要模仿编译器的行为把 array[i][j] 这样的式子手工转变为

*( (int*) array + n*i + j );

然后,一切是显得那么祥和!^_^

最后,为了避免错误,我们可以将二维或高维数组做参数转换为一维数组做参数的情形。这也是基于多维数组在内存中的连续存储方式而可行! 

综上可观,传入行参为指针是实用的,但要注意转换指针的类型1.int function( int **array, int rows, int columns ); // func( (int**)array,  2,  5 ); 2.int function( int *a, int rows, int columns ); // func( (int*)array,  2,  5 );

 

有趣的数组

2014年5月10日 15:42

#include <iostream>
 
using namespace std;
 
int main()
{
    int arr[10] ={1,2,2,4,5};
    cout << sizeof(arr)/sizeof(int) << endl;
    cout << arr[6] << endl;
    return 0;
}
 
10
0

判断主机的字节序

2014年4月25日 16:50

#include <stdio.h>
 
typedef union 
{
    short s;
    char c[sizeof(short)];
} Utool; 
 
 
int main(int argc, char **argv)
{
    Utool un;
    un.s = 0x0102;
    if(sizeof(short) == 2)
    {
   if(un.c[0]==1 && un.c[1]==2)
       printf("big-endian\n");
   else if(un.c[0]==2 && un.c[1]==1)
       printf("little-endian\n");
   else
       printf("unknowable!\n");
    }
    return 0;
}

latex编译的makefile文件

2014年4月21日 00:59

FILENAME=name
 
FILES=acmsmall.cls algorithm2e.sty
 
TMP=$(FILENAME).aux $(FILENAME).log $(FILENAME).dvi $(FILENAME).ps $(FILENAME).out
 
ALL: $(FILENAME).tex $(FILES)   #依赖规则
        latex $(FILENAME).tex   #命令行,三者不在同一个shell中执行
        dvips $(FILENAME).dvi
        ps2pdf $(FILENAME).ps
 
read:
        evince $(FILENAME).pdf 
 
clean:
        -rm $(TMP)
 

linux查看.jpg .ps .pdf

2014年4月20日 21:08

1.使用gs或evince命令可以查看ps及pdf文件,若无法查看ps文件,可以用ps2pdf命令将ps文件转化为pdf文件

 

$ ps2pdf test6.ps test6.pdf

 

另外,如果在服务器不能够用上面的命令看ps文件,也可以先用ps2pdf将其转化为pdf文件,然后用xpdf查看pdf文件

 

$ xpdf test6.pdf

 

2.查看jpg文件

 

$ eog test1.jpg

 

$ display test1.jpg

Install LaTex in Ubuntu

2014年4月17日 20:21

Forewords

 This g uide explains how to install LaTeX in Ubuntu Linux. LaTeX is a document preparation system for high-quality typesetting. It is most often used for medium-to-large technical or scientific documents but it can be used for almost any form of publishing.

LaTeX is not a word processor! Instead, LaTeX encourages authors not to worry too much about the appearance of their documents but to concentrate on getting the right content.

Installing LaTeX is also compatible to any hosting, Just make sure that the hosting you have is a reliable one.

 

How to install LaTeX in Ubuntu

In Ubuntu Linux, you have to first install LaTeX to use it. This is how LaTeX is installed in Ubuntu.

$ sudo apt-get install texlive

The above command will install a basic subset of TeX Live’s functionality. To install all the packages in the LaTeX distribution, you have to run the following command.

$ sudo apt-get install texlive-full

Gedit LaTeX Plugin

Gedit has a plugin for LaTeX which converts Gedit into a LaTeX editor. You can install the Gedit LaTeX plugin as follows :

$ sudo apt-get install gedit-latex-plugin

Once you install the plug-in, you will have to enable the plug-in in Gedit to begin using it. This is achieved by opening Gedit Preferences (GEdit > Edit > Preferences). Then clicking on the Plugins tab and turning on the “Gedit LaTeX plugin”. Now when ever you open a TeX file, you will have access to the LaTeX menu in Gedit.

Recommended LaTeX Packages

  • latex-beamer – Beamer package is used to create presentations. It is an excellent LaTeX class that supports dynamic effects.
  • TeXPower – Is a bundle of style and class files for creating dynamic online presentations with LaTeX.
  • Prosper – A LaTeX class for writing transparencies.
  • texlive-pictures – This is a LaTeX package for drawing graphics. It contain several classes such as ‘curve’ (for creating resumes), ‘bardiag’ (for bar graphs), ‘pmgraph’ (poor man’s graphics) and so on.
  • texlive-latex-extra – This is a large collection of addon packages for LaTeX. The full list of classes in this package are listed here.

This is the full command I used to install LaTeX on my machine running Ubuntu Linux.

$ sudo apt-get install gedit-latex-plugin texlive-fonts-recommended latex-beamer texpower texlive-pictures texlive-latex-extra texpower-examples imagemagick

C和指针易错区

2014年4月02日 20:11

1.char ch;

...

while( (ch = getchar()) != EOF )

...

注意:EOF需要的位数比字符型值所能提供的位数要多,这也是getchar返回一个整型值而不是字符值的原因。然而以上程序将getchar()的返回值首先存储于ch中,这将会导致截断,程序可移植性降低。

一般的,在比较字符型与整型大小时,可以将字符型变量声明为整型变量,这样便于比较。

2.为了保持最佳的可移植性,把字符的值限制在有符号和无符号字符的范围的交集之内,即0~127。

3.sizeof( a = b+1 );语句是不会对表达式 a = b+1 进行赋值运算的。

4.++a = 10; 此语句在g++编译中是可以通过的,但在gcc编译中不能通过。即在gcc中,编译器会将 ++a 看作一个表达式,它的结果是a值的一个拷贝,而不是其本身,你只能用它;但在g++中,编译器将其看作是a本身。

5.逗号表达式是从左向右逐个进行求值,整个逗号表达式的值是最后那个表达式的值。看下面程序:

while( a = get_value(), count_value(a), a>0 )

{

    ...

}

其等价于:

a = get_value();

count_value(a);

while( a>0 )

{

     ...

    a = get_value();

    count_value(a);

}

6.int a = 60000;

int b = 4000;

long c = a*b;

此程序易出现问题,a*b的值可能溢出,要写为: long c = (long)a * b; 这样就进行自动类型转换了。 

7.4个可以对整个表达式的求值顺序施加控制的操作符是:&&,||,?: 和 , 。

8.注意 *p++ , (1)++操作符产生p的一份拷贝(2)然后++操作符增加p的值(3)最后在p的拷贝上执行间接访问操作。另外++操作符的优先级高于*操作符。

9.标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向数组第一个元素之前的那个内存位置的指针进行比较。

10.int a[SIZE];

int* b;

b = a;

cout << b[0] ;

cout << b[-1];

cout << 2[a];

cout << 2[b];

以上cout都是合法的。

11.对于自动变量,为何不能像静态变量或者全局变量那样可以被自动赋初值。是因为自动变量位于运行时堆栈中,执行流每次进入它所在的代码块时,这类变量每次所处的内存位置可能并不相同。

12.char message[] = "hello";   char *message = "hello";    string  message = "hello"; 以及 char message[] = {'h','e','l','l','o'};是相同的效果,但是要记得“hello”中是要多一个字符'\0'的。被赋值为"hello"的变量(不论是指针还是数组)都将被视为指针,当输出时,cout<< message;就会输出hello,特别注意当形式写为 char message[] = "hello"; 时cout<< message;的值,很具有迷惑性。

int main()
    char* c = "hello";
    char m[] = "world";
    char h[3] = {'p','\0','q'};
    printf("%c\n", c);//这条语句是错的
    printf("%s\n", c);
    printf("%c\n", *c);
    printf("%s\n", m);
    printf("%c\n", *m);
    printf("%s\n", h);//下面两条语句输出也是一样
    printf("%c\n", *h);
    cout << h << endl;//下面这两条语句要好好考虑了,输出结果是一样的
    cout << *h << endl;
    return 0;
}
13.数组 array[3,4],是完全合法的,其[]内部为一逗号表达式,结果与array[4]等价。
14.int (*p)[10];声明了一个指向包含10个整型元素的数组的指针。
15.int a[][2] = {1,2,3,4,5};等价于 int a[3][2] = {
                                                                                    {1,2},
                                                                                    {3,4},
                                                                                    {5,0}
                                                                            };
16.库函数strlen原型为:size_t strlen( char const *string ); size_t是一个无符号整数类型。注意以下两个语句:1)if( strlen(x) >= strlen(y) )   2)  if( strlen(x) - strlen(y) >= 0).此两条语句并不等价,第二条语句中无符号数相减永远是无符号数,故其永为真。另外,谨慎将无符号数与有符号数进行运算。
17.结构体和类的数据存储分配。其遵循边界对齐原则。
class example
{
    char a;
    char b;
    int c;
    char d;
};
int main()
    example e;
    cout << sizeof(e) << endl;
    return 0;
}
其输出为12 。
如果改为:
class example
{
    char a;
    char b;
    char c;
    int d;
};
其输出为8 。
18.如果想知道结构体或者类中某个成员的实际位置,可以使用offsetof(定义在stddef.h):offsetof( type, member ),其结果是一个size_t值,表示这个指定成员开始存储的位置距离结构开始存储的位置偏移字节数。
19.联合(union)的所有成员引用的是内存中的相同位置,当你想在不同时刻把不同的东西存储于同一个位置时,就可以使用联合了。
union fi
{
    float f;
    int i;
};//联合的定义

当联合的各个成员具有不同的长度,其的长度就是它最长成员的长度。当存储成员的长度差异较大时,为了避免内存浪费,采取存储指针。其可以初始化,但初始值只能与第一个成员的类型匹配。

19.int fun();//此为一个函数声明

int (*p)() = &fun; 或者 int (*p)() = fun;//函数名被解释为指向函数入口地址的指针

int value;

value = fun();

value = (*p)();

value = p();

以上三条调用函数语句是等价的,编译器在执行函数调用操作真正是需要函数在内存中的位置,执行是开始于其地址的,所以前两条语句是要由编译器将函数名转换为函数指针。

20.字符串常量。

cout << "xyz";// xyz

cout << "xyz"+1;// yz

cout <<  "xyz"[2];// z

cout << *"xyz";// x

cout << *("xyz" + 1);// y

字符串"xyz"其实质上是一个指针常量。

21.如果 一个现存的名字要被#define重新定义,那么它的旧定义首先必须用#undef移除。

22.NULL是字符串终止符,它本身并不是字符串的一部分,所以字符串的长度并不包括NULL字节,NULL其表现为 '\0' 。

23. strcmp函数返回值为int类型(1,0,-1),而非bool类型。注意错误用法if(strcmp(s1,s2))。

24.当用strncpy函数将源字符串的字符复制到目标数组,如果strlen(src)的值大于或等于len,那么只有len个字符被复制道des中,注意!其结果将不会以NULL字节结尾,而strncat函数始终都会在结尾加上NULL字符。如下程序:

char    buffer[BSIZE];

strncpy( buffer, name, BSIZE );

buffer[BSIZE-1] = '\0';

这样能很好预防出现由strncpy函数得到的结果不以NULL字节结尾。

cout格式输出

2014年4月02日 02:51

// 方法1

cout<<hex<<i<<endl; //输出十六进制数
cout<<oct<<i<<endl; //输出八进制数
cout<<dec<<i<<endl; //输出十进制数

// 方法2

// 输出16进制, setbase(int)可以设置8等。

 cout << setbase(16) << i << endl;

// 方法3

 setiosflags(ios::showbase);
 cout << hex << i << endl;

void main()
{
int x=30, y=300, z=1024;
cout<<x<<' '<<y<<' '<<z<<endl; //按十进制输出
cout.setf(ios::showbase | ios::uppercase); //设置基指示符输出和数值中的字母大写输出
cout<<x<<' '<<y<<' '<<z<<endl;
cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符输出和数值中的字母大写输出
cout.setf(ios::oct); //设置为八进制输出,此设置不取消一直有效
cout<<x<<' '<<y<<' '<<z<<endl; //按八进制输出
cout.setf(ios::showbase | ios::uppercase); //设置基指示符输出和数值中的字母大写输出
cout<<x<<' '<<y<<' '<<z<<endl;
cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符输出和数值中的字母大写输出
cout.unsetf(ios::oct); //取消八进制输出设置,恢复按十进制输出
cout.setf(ios::hex); //设置为十六进制输出
cout<<x<<' '<<y<<' '<<z<<endl;
cout.setf(ios::showbase | ios::uppercase); //设置基指示符输出和数值中的字母大写输出
cout<<x<<' '<<y<<' '<<z<<endl;
cout.unsetf(ios::showbase | ios::uppercase); //取消基指示符输出和数值中的字母大写输出
cout.unsetf(ios::hex); //取消十六进制输出设置,恢复按十进制输出
cout<<x<<' '<<y<<' '<<z<<endl;
}

几种类型的sizeof

2014年4月01日 02:07

#include <iostream>
using namespace std;
 
int main()
    char *c ="hello";
    int *a[2][3];
    int b[2][3];
    cout << sizeof(a) << endl
        << sizeof(b) << endl
        << sizeof(c) << endl;
    return 0;
}
 
运行结果:(注意系统是32位)
24
24
4
 

 

vector的erase操作

2014年4月01日 00:56

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
      if( *iter == 3)
             iter = veci.erase(iter);
}

这段代码是错误的:1)无法删除两个连续的"3"; 2)当3位于vector最后位置的时候,也会出错(在veci.end()上执行 ++ 操作)

正确的代码应该为:

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); )
{
     if( *iter == 3)
          iter = veci.erase(iter);
      else
            iter ++ ;
}