Posts Tagged ‘C’

August 7, 2011

使用变参

  C/C++提供了函数的可变参数(variadic)机制,大部分人写的第一个C程序恐怕就是Hello World吧,使用的应该也是printf(“Hello, World\n”)。printf就是一个使用可变参数的典型,它的原型声明为,

int printf(const char *fmt, ...);

  其中返回值为实际输出字符个数,fmt为格式控制字符串,而”…”便声明了一个可变参数,你可以根据传递0个或多个参数给printf。printf内部会根据格式控制串中的格式指定符号(d, f, p等等)来逐个解析通过可变参数传进的实参变量。
  为解析可变参数,C语言提供了一个va_list类型和四个宏,分别是va_start, va_arg, va_end, 和va_copy,这些宏声明在stdarg.h中。

Tags: ,,. 268 views
April 9, 2011

  头文件中通常包含有:函数原型(声明)、宏定义、内联函数定义。
  头文件使用#include宏命令引入。有两种形式:#inlcude <header.h>和#include “header.h”. 两种形式的区别在于预处理器(preprocessor)查找头文件的方式的不同:对于前者,预处理器仅在系统预定义的标准路径中查找(标准查找路径由环境变量指明),比如/usr/include, /usr/local/include;对于后者,预处理器首先查找(源文件所在的)当前目录,若未找到,则到标准路径查找。另外,查找路径还可以通过编译器选项(-I for gcc)指定。通常,对于C/C++标准库和其他系统范围的程序库,使用<>形式,对于程序本身定义的头文件,采用”"形式。

Tags: ,. 126 views
October 22, 2010

  不多说,都在代码里了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
int
main(int AC, char **AV)
{
    FILE *fd = fopen("data", "w+");
    fprintf(fd, "%x%c", 0x41, '1');
    fseek(fd, 0, SEEK_SET);
    int n;
    fscanf(fd, "%d", &n);
    fseek(fd, 0, SEEK_SET);
    char s[4];
    int c = fread(s, 1, sizeof(s), fd);
    s[c] = '\0';
    printf("%d, %s\n", n, s);
    fclose(fd);
    return 0;
}
Tags: . 202 views
October 5, 2010

  在StackOverflow上面看到的,分析一下下面的代码,对初学者理解什么是堆,什么是栈,对象是如何拷贝的有所帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
typedef struct node
{
      int i;
      struct node *next;
}node;
node getnode(int a)
{
      struct node n;
      n.i=a;
      n.next=NULL;
      return n;
}
Tags: . 256 views
September 19, 2010

  那么,C/C++中,哪些地方是顺序点呢?

  • 每个表达式的结束处;
  • 函数调用中,在所有参数求值完成后,函数体开始执行前有一个顺序点,而参数间的逗号处则没有顺序点。所以f(++i, ++i)的行为也是未定义的;
  • 逻辑运算符&&、||还有条件运算符?:的第一个参数末尾处有一个顺序点;
  • 逗号表达式中每一个逗号处有一个顺序点。因此x = (++i, ++i)是有确定行为的;
  • 在每一个完整的变量声明处有一个顺序点,例如int i, j;中逗号和分号处分别有一个顺序点;
  • for循环控制条件中的两个分号处各有一个顺序点。

  那么,现在,这个程序有问题吗?

1
2
3
4
5
6
7
8
9
int
main()
{
    int m = 1, n = 0;
    printf("%d, %d\n", m, n);
    m ^= n ^= m ^= n;
    printf("%d, %d\n", m, n);
    return 0;
}
Tags: ,,. 253 views
July 6, 2010

  对qsort需要注意几点:

  • qsort中第一个参数是待排序数组的开始地址,既然是数组,各元素就是同类型、同大小的对象,且数组是“一维数组”(即地址是连续的);
  • qsort用以区分对象的依据是第二和第三个参数,分别表示对象个数和每个对象的大小(字节);
  • qsort并不知道每个对象的类型和结构,排序准则由用户在第四个参数(比较函数)中指出,qsort按该比较函数准则的“升序”对数组进行排序;
  • 标准C不支持运算符重载,各对象的交换(因为这是qsort)靠的是逐字节的拷贝(memcpy?)。

  在上面的两片代码中,待排序的对象一个是字符型指针,一个是char (*)[10]型数组。然后,就没有然后了。

Tags: ,,. 136 views
May 21, 2010

  在形如struct structName varName;的语句中,struct是必须的吗?这是一个显而易见的语法问题,但却容易被忽略,尤其容易被C+C++的同志们忽略。
  在标准C中,struct关键字是必须的:

1
2
3
4
5
6
7
8
9
10
struct structName {
    int n;
};
//~ typedef struct structName structName;
int
main()
{
    struct structName n;
    return 0;
}

若没有前置的struct关键字,上面的代码就不能通过编译。我的gcc会提示”structName” undeclared, parse error before ‘n’的错误。为了方便,通常会使用typedef struct structName structName;语句来为struct structName定义类型别名。
  但是,在C++中,一般情况下,struct/class关键字就不是必须的。但是,在有些情况下struct/class关键字又是必须的,因为这时的名字structName有歧义性。这是因为,C/C++语言允许用户自定义类型和函数同名。

Tags: ,. 95 views
November 28, 2009
1
2
3
4
5
6
7
8
9
10
11
12
13
void fun1(char * str) {}
void fun2(char ** str) {}
 
//~ int main(int argc, char ** argv)
int main(int argc, char * argv[])
{
	char str1[] = "Hello, Piggy!";
	char str2[][4] = "Hello, Piggy!";
	fun1(str1);
	fun2(str2);
	fun2(&str1);
	return 0;
}

  上面的snippet有错误吗?有几个?你能找出来并说出原因吗?4、5两行有区别吗?想一下,然后看gcc给出的错误信息,

Tags: . 42 views
November 14, 2009

  看Chris对内联的总结,说到内联函数在编译时会被放入”符号表”,想一探究竟,结果却发现另外一个问题,疑惑不解。

1
2
3
4
5
6
7
#include <stdio.h>
inline int add(int a, int b) { return a + b; }
int main()
{
	int n = add(1,2);
	return 0;
}
Tags: ,,. 31 views
November 3, 2009

  这里面猫腻儿还真不少。

  karmic到源里面没有以前到vim-full包了,取而代之到是vim包,但现在有很多问题,n”+yy和n”+p无法和系统”剪切板”里到内容关联了,不知道什么原因。

Update
  一切都释然了,只要意识到,>也需要进行类型提升。那么后面到-1啦-2啦之类的,都是很大很大的数了,循环根本就进不去,更别提死循环了。这样看来四、五两段程序就没有必要列出来了。其实,我是被它们的汇编代码给迷惑住了。

Tags: ,,. 27 views
Page 1 of 3123