`

c,vc常见错误

 
阅读更多

http://www.vc91.com/bbs/dispbbs.asp?boardid=12&id=30

1.书写标识符时,忽略了大小写字母的区别。 main() { int a=5; printf("%d",A); } 编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。

2.忽略了变量的类型,进行了不合法的运算。 main() { float a,b; printf("%d",a%b); } %是求余运算,得到a/b的整余数。整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。

3.将字符常量与字符串常量混淆。 char c; c="a"; 在这里就混淆了字符常量与字符串常量,字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列。C规定以“”作字符串结束标志,它是由系统自动加上的,所以字符串“a”实际上包含两个字符:‘a'和‘',而把它赋给一个字符变量是不行的。

http://publishblog.blogchina.com/blog/tb.b?diaryID=3035523

C语言之指针综合谈- -

 概述

  Joel Spolsky认为,对指针的理解是一种aptitude,不是通过训练就可以达到的。虽然如此,我还是想谈一谈这个C/C++语言中最强劲也是最容易出错的要素。

  鉴于指针和目前计算机内存结构的关联,很多C语言比较本质的特点都孕育在其中,因此,本篇和第六、第七两篇我都将以指针为主线,结合在实际编程中遇到的问题,来详细谈谈关于指针的几个重要方面。

  指针类型的本质分析

  1、指针的本质

  指针的本质:一种复合的数据类型。下面我将以下面几个作为例子进行展开分析:

  a)、int *p;
  b)、int **p;
  c)、int (*parValue)[3];
  d)、int (*pFun)();

  分析:

  所谓的数据类型就是具有某种数据特征的东东,比如数据类型char,它的数据特征就是它所占据的内存为1个字节, 指针也很类似,指针所指向的值也占据着内存中的一块地址,地址的长度与指针的类型有关,比如对于char型指针,这个指针占据的内存就是1个字节,因此指针也是一种数据类型,但我们知道指针本身也占据了一个内存空间地址,地址的长度和机器的字长有关,比如在32位机器中,这个长度就是4个字节,因此指针本身也同样是一种数据类型,因此,我们说,指针其实是一种复合的数据类型,

  好了,现在我们可以分析上面的几个例子了。

  假设有如下定义:
int nValue;


  那么,nValue的类型就是int,也就是把nValue这个具体变量去掉后剩余的部分,因此,上面的4个声明可以类比进行分析:

  a)、int *

  *代表变量(指针本身)的值是一个地址,int代表这个地址里面存放的是一个整数,这两个结合起来,int *定义了一个指向整数的指针,类推如下:

  b)、int **

  指向一个指向整数的指针的指针。

  c)、int (*)[3]

  指向一个拥有三个整数的数组的指针。

  d)、int (*)()

  指向一个函数的指针,这个函数参数为空,返回值为整数。

  分析结束,从上面可以看出,指针包括两个方面,一个是它本身的值,是一个内存中的地址;另一个是指针所指向的物,是这个地址中所存放着具有各种各样意义的数据。

  2、对指针本身值的分析

  下面例子考察指针本身的值(环境为32位的计算机):
void *p = malloc( 100 );


  请计算sizeof ( p ) = ?
char str[] = “Hello” ;
char *p = str ;


  请计算sizeof ( p ) = ?
void Func ( char str[100])
{
请计算 sizeof( str ) = ? //注意,此时,str已经退化为一个指针,详情见
//下一篇指针与数组
}

  分析:上面的例子,答案都是4,因为从上面的讨论可以知道,指针本身的值对应着内存中的一个地址,它的size只与机器的字长有关(即它是由系统的内存模型决定的),在32位机器中,这个长度是4个字节。

  3、对指针所指向物的分析

  现在再对指针这个复合类型的第二部分,指针所指向物的意义进行分析。

  上面我们已经得到了指针本身的类型,那么将指针本身的类型去掉 “*”号就可得到指针所指向物的类型,分别如下:

  a)、int

  所指向物是一个整数。

  b)、int*

  所指向物是一个指向整数的指针。

  c)、int ()[3]

  ()为空,可以去掉,变为int [3],所指向物是一个拥有三个整数的数组。

  d)、int ()()

  第一个()为空,可以去掉,变为int (),所指向物是一个函数,这个函数的参数为空,返回值为整数。

  4、附加分析

  另外,关于指针本身大小的问题,在C++中与C有所不同,这里我也顺带谈一下。

  在C++中,对于指向对象成员的指针,它的大小不一定是4个字节,这主要是因为在引入多重虚拟继承以及虚拟函数的时候,有些附加的信息也需要通过这个指针进行传递,因此指向对象成员的指针会增大,不论是指向成员数据,还是成员函数都是如此,具体与编译器的实现有关,你可以编写个很小的C++程序去验证一下。另外,对一个类的静态成员(static member,可以是静态成员变量或者静态成员函数)来说,指向它的指针只是普通的函数指针,而不是一个指向类成员的指针,所以它的大小不会增加,仍旧是4个字节。
----------------------------------------------------------------------------

指针本身的相关问题

  1、问题:空指针的定义

  曾经看过有的.h文件将NULL定义为0L,为什么?

  答案与分析:

  这是一个关于空指针宏定义的问题。指针在C语言中是经常使用的,有时需要将一个指针置为空指针,例如在指针变量初始化的时候。
C语言中的空指针和Pascal或者Lisp语言中的NIL具有相同的地位。那如何定义空指针呢?下面的语句是正确的:
char *p1 = 0;
int *p2;
if (p != 0)
{
...
}
p2 = 0;


  也就是说,在指针变量的初始化、赋值、比较操作中,0会被编译器理解为要将指针置为空指针。至于空指针的内部表示是否是0,则随不同的机器类型而定,不过通常都是0。但是在另外一些场合下,例如函数的参数原型是指针类型,函数调用时如果将0作为参数传入,编译器则不能将其理解为空指针。此时需要明确的类型转换,例如:
void func (char *p);
func ((char *)0);


  一般情况下,0是可以放在代码中和指针关联使用的,但是有些程序员(数量还不少呦!也许就包括你在内)不喜欢0的直白,认为其不能表示作为指针的特殊含义,于是要定义一个宏NULL,来明确表示空指针常量。这也是对的,人家C语言标准就明确说:“ NULL应该被定义为与实现相关的空指针常量”。但是将NULL定义成什么样的值呢?我想你一定见过好几种定义NULL的方法:
#define NULL 0
#define NULL (char *)0
#define NULL (void *)0


  在我们使用的绝大多数计算系统上,例如PC,上述定义是能够工作的。然而,世界上还有很多其它种类的计算机,其CPU也不是Intel的。在某些系统上,指针和整数的大小和内部表示并不一致,甚至不同类型的指针的大小都不一致。为了避免这种可移植性问题,0L是一种最为安全的、最妥帖的定义方式。0L的含义是: “值为0的整数常量表达式”。这与C语言给出的空指针定义完全一致。因此,建议采用0L作为空指针常量NULL的值。

  其实 NULL定义值,和操作系统的的平台有关, 将一个指针定义为 NULL, 其用意是为了保护操作系统,因为通过指针可以访问任何一块地址, 但是,有些数据是不许一般用户访问的,比如操作系统的核心数据。 当我们通过一个空(NULL)的指针去方位数据时,系统会提示非法, 那么系统又是如何知道的呢??

  以windows2000系统为例, 该系统规定系统中每个进程的起始地址(0x00000000)开始的某个地址范围内是存放系统数据的,用户进程无法访问, 所以当用户用空指针(0)访问时,其实访问的就是0x00000000地址的系统数据,由于该地址数据是受系统保护的,所以系统会提示错误(指针访问非法)。

  这也就是说NULL值不一定要定义成0,起始只要定义在系统的保护范围的地址空间内,比如定义成(0x00000001, 0x00000002)都会起到相同的作用,但是为了考虑到移植性,普遍定义为0 。

  2、问题:与指针相关的编程规则&规则分析

  指针既然这么重要,而且容易出错,那么有没有方法可以很好地减少这些指针相关问题的出现呢?

  答案与分析:

  减少出错的根本是彻底理解指针。

  在方法上,遵循一定的编码规则可能是最立竿见影的方法了,下面我来阐述一下与指针相关的编程规则:

  1) 未使用的指针初始化为NULL 。

  2) 在给指针分配空间前、分配后均应作判断。

  3) 指针所指向的内容删除后也要清除指针本身。

  要牢记指针是一个复合的数据结构这个本质,所以我们不论初始化和清除都要同时兼顾指针本身(上述规则1,3)和指针所指向的内容(上述规则2,3)这两个方面。

  遵循这些规则可以有效地减少指针出错,我们来看下面的例子:
void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, “hello”);
 free(str);
 if(str != NULL)
 {
  strcpy(str, “world”);
  printf(str);
 }
}


  请问运行Test函数会有什么样的结果?

  答:

  篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。

  如果我们牢记规则3,在free(str)后增加语句:
str = NULL;


  那么,就可以防止这样的错误发生。

http://bbs.gliet.edu.cn/bbs/index.php?showtopic=116177

一.指针。
它的本质是地址的类型。在许多语言中根本就没有这个概念。但是它却正是C灵活,高效,在面向过程的时代所向披靡的原因所在。因为C的内存模型基本上对应了现在von Neumann(冯·诺伊曼)计算机的机器模型,很好的达到了对机器的映射。不过有些人似乎永远也不能理解指针【注1】。
注1:Joel Spolsky就是这样认为的,他认为对指针的理解是一种aptitude,不是通过训练就可以达到的

http://www.joelonsoftware.com/pr ... /fog0000000073.html

指针可以指向值、数组、函数,当然它也可以作为值使用。
看下面的几个例子:
int* p;//p是一个指针,指向一个整数
int** p;//p是一个指针,它指向第二个指针,然后指向一个整数
int (*pa)[3];//pa是一个指针,指向一个拥有3个整数的数组
int (*pf)();//pf是一个指向函数的指针,这个函数返回一个整数
后面第四节我会详细讲解标识符(identifier)类型的识别。
1.指针本身的类型是什么?
先看下面的例子:int a;//a的类型是什么?
对,把a去掉就可以了。因此上面的4个声明语句中的指针本身的类型为:
int*
int**
int (*)[3]
int (*)()
它们都是复合类型,也就是类型与类型结合而成的类型。意义分别如下:
point to int(指向一个整数的指针)
pointer to pointer to int(指向一个指向整数的指针的指针)
pointer to array of 3 ints(指向一个拥有三个整数的数组的指针)
pointer to function of parameter is void and return value is int (指向一个函数的指针,这个函数参数为空,返回值为整数)
2.指针所指物的类型是什么?
很简单,指针本身的类型去掉 “*”号就可以了,分别如下:
int
int*
int ()[3]
int ()()
3和4有点怪,不是吗?请擦亮你的眼睛,在那个用来把“*”号包住的“()”是多余的,所以:
int ()[3]就是int [3](一个拥有三个整数的数组)
int ()()就是int ()(一个函数,参数为空,返回值为整数)【注2】
注2:一个小小的提醒,第二个“()”是一个运算符,名字叫函数调用运算符(function call operator)。
3.指针的算术运算。
请再次记住:指针不是一个简单的类型,它是一个和指针所指物的类型复合的类型。因此,它的算术运算与之(指针所指物的类型)密切相关。
int a[8];
int* p = a;
int* q = p + 3;
p++;
指针的加减并不是指针本身的二进制表示加减,要记住,指针是一个元素的地址,它每加一次,就指向下一个元素。所以:
int* q = p + 3;//q指向从p开始的第三个整数。
p++;//p指向下一个整数。
double* pd;
……//某些计算之后
double* pother = pd – 2;//pother指向从pd倒数第二个double数。
4.指针本身的大小。
在一个现代典型的32位机器上【注3】,机器的内存模型大概是这样的,想象一下,内存空间就像一个连续的房间群。每一个房间的大小是一个字节(一般是二进制8位)。有些东西大小是一个字节(比如char),一个房间就把它给安置了;但有些东西大小是几个字节(比如double就是8个字节,int就是4个字节,我说的是典型的32位),所以它就需要几个房间才能安置。
注3:什么叫32位?就是机器CPU一次处理的数据宽度是32位,机器的寄存器容量是32位,机器的数据,内存地址总线是32位。当然还有一些细节,但大致就是这样。16位,64位,128位可以以此类推。
这些房间都应该有编号(也就是地址),32位的机器内存地址空间当然也是32位,所以房间的每一个编号都用32位的二进制数来编码【注4】。请记住指针也可以作为值使用,作为值的时候,它也必须被安置在房间中(存储在内存中),那么指向一个值的指针需要一个地址大小来存储,即32位,4个字节,4个房间来存储。
注4:在我们平常用到的32位机器上,绝少有将32位真实内存地址空间全用完的(232 = 4G),即使是服务器也不例外。现代的操作系统一般会实现32位的虚拟地址空间,这样可以方便运用程序的编制。关于虚拟地址(线性地址)和真实地址的区别以及实现,可以参考《Linux源代码情景分析》的第二章存储管理,在互联网上关于这个主题的文章汗牛充栋,你也可以google一下。
但请注意,在C++中指向对象成员的指针(pointer to member data or member function)的大小不一定是4个字节。为此我专门编制了一些程序,发现在我的两个编译器(VC7.1.3088和Dev-C++4.9.7.0)上,指向对象成员的指针的大小没有定值,但都是4的倍数。不同的编译器还有不同的值。对于一般的普通类(class),指向对象成员的指针大小一般为4,但在引入多重虚拟继承以及虚拟函数的时候,指向对象成员的指针会增大,不论是指向成员数据,还是成员函数。【注5】。
注5:在Andrei Alexandrescu的《Modern C++ Design》的5.13节Page124中提到,成员函数指针实际上是带标记的(tagged)unions,它们可以对付多重虚拟继承以及虚拟函数,书上说成员函数指针大小是16,但我的实践告诉我这个结果不对,而且具体编译器实现也不同。一直很想看看GCC的源代码,但由于旁骛太多,而且心不静,本身难度也比较高(这个倒是不害怕),只有留待以后了。
还有一点,对一个类的static member来说,指向它的指针只是普通的函数指针,不是pointer to class member,所以它的大小是4。
5.指针运算符&和*
它们是一对相反的操作,&取得一个东西的地址(也就是指针),*得到一个地址里放的东西。这个东西可以是值(对象)、函数、数组、类成员(class member)。
其实很简单,房间里面居住着一个人,&操作只能针对人,取得房间号码;
*操作只能针对房间,取得房间里的人。
参照指针本身的类型以及指针所指物的类型很好理解。
小结:其实你只要真正理解了1,2,就相当于掌握了指针的牛鼻子。后面的就不难了,指针的各种变化和C语言中其它普通类型的变化都差不多(比如各种转型)。

http://bbs.ncre.cn/archiver/?tid-57374.html

yinbenli2006-1-3 14:27

C常见错误新手看,高手闪

1. 数据溢出
int a = 32767;
a = a + 1;

此时a的值为 –32768

2. (-1)&&(-1) 值为:1
非0的数,逻辑值均为1
只有数0,逻辑值为0

3. 设a=5, b=6, c=7, d=8, m=2, n=2
执行 (m = a > b) && ( n = c > b)
结果:n 的值为 2
解析:&&是短路(shortway)运算符,当&&左边表达式的值为0时,
不再执行右边的表达式

4. 1 / 2 = 0
1.0 / 2 = 0.5

5. 转义字符
遇到’/’字符应注意转义字符问题,比如’//’,’/ddd’就是转义字符
常见考法:Q:”a/045+045/b”有几个字节?
A:8个字节(分别是’a’,’/045’,’+’,’0’,’4’,’5’,’/b’,’/0’)

字符串结束符
如上题,”a/045+045/b”含有最后的字符串结束符’/0’,因而长度为8个字节
注意:计算字符串长度时,sizeof会将’/0’计算在内,strlen()则不算

Main()
{
char b[] = “hello, you”;
b[5] = 0;
printf(“%s/n”, b);
}

运行结果:hello
解析:b[5]=0 ;等价于 b[5] = ‘/0’;


6. ++ i , i ++
x = 5;
y1 = x++ * x++;
y2 = ++x * ++x;

此时y1的值为25,y2的值为49

7. printf
l 考法1
x = 11, y = 10;
printf(“%d, %d”, (x++, y), y++);

输出结果:11,10
解析:
1) printf函数按参数从右到左顺序进行分析
y++ -> x++ -> y
| |
10,后y变11 11
2) 分析结束,输出顺序是从左到右;即:11, 10
l 考法2
printf(“%4s”, “abc”); // 输出结果 (空格)abc
printf(“%-4s”, “abc”); // 输出结果 abc(空格)
printf(“%4s”, “abcde”); // 输出结果 abcde
printf(“%9.3f”, 12.3456); // 输出结果 1.234e+01

8. scanf
scanf(“%7.2f”, &a); // 错,不能规定精度
scanf(“%3d”, &a); // 正确
scanf(“%d:%d”, &a, &b); // 输入格式:(整数):(整数) 例 12:34
scanf(“%3c”, &ch); // 正确。但是ch只取输入字符中的第一个字符
// 例:输入abc,则ch值为’a’

9. 注意switch中的break

10. while (a = 1) { … } // 注意这里是赋值号

11. for( x = 0, y = 3, i = 0; (y > 3)&&(x < 4); x++, y++ ) i++;
运行结果 i = 0
解析:for循环运行过程 表达式1->表达式2-> 循环体->表达式3

12. 数组
int a[10] = {0, 1, 2, 3} // 正确。前四个元素赋值,后6个元素全为0

int a[2][2] = {1,2,3,4} // 正确
int a[ ][2] = {1,2,3,4} // 正确。第一维可以省略
int a[2][ ] = {1,2,3,4} // 错误。非第一维不能省略

13. 预处理
定义宏:#define s(x) x*x
表达式 s(a+b) 宏展开为: a + b*a + b

定义宏:#define s(x) (x)*(x)
表达式 s(a+b) 宏展开为: (a + b)*(a + b)

14. 指针
l 若定义: int a[10], *p; p = a;
则: a + i 是地址
*(a+i) 是地址a + i的内容
l 数组是指针
*(a+i) 和 *(p+i) 是等价的
a[i] 和 p[i]是等价的
l 字符串也是指针
若定义: char *sp = “bug”;
char s[] = {‘b’,’u’,’g’};
则: s与sp是等价的

15. 函数
l 值传递:
Void swap1(int a, int b)
{
int c = a;
a = b;
b = c;
}
void main()
{
int x = 1, y = 2;
swap1(x, y);
printf(“%d, %d”, x, y);
}

程序运行输出结果:1,2
可见x与y变量的值没有交换
l 地址传递:
Void swap2(int *a, int *b)
{
int *c = a;
*a = *b;
*b = *c;
}
void main()
{
int x = 1, y = 2;
swap1(&x, &y);
printf(“%d, %d”, x, y);
}

程序运行输出结果:2,1
可见x与y变量的值实现了交换

http://www.topice.net/Html/c/2006-6/9/145210397.html

水滴石穿C语言之指针、数组和函数
作者:佚名 来源:网络 日期:2006-3-30


  基本解释

  1、指针的本质是一个与地址相关的复合类型,它的值是数据存放的位置(地址);数组的本质则是一系列的变量。

  2、数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。

  3、当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。

  问题:指针与数组

  听说char a[]与char *a是一致的,是不是这样呢?

  答案与分析:

  指针和数组存在着一些本质的区别。当然,在某种情况下,比如数组作为函数的参数进行传递时,由于该数组自动退化为同类型的指针,所以在函数内部,作为函数参数传递进来的指针与数组确实具有一定的一致性,但这只是一种比较特殊的情况而已,在本质上,两者是有区别的。请看以下的例子:
char a[] = "Hi, pig!";
char *p = "Hi, pig!";


  上述两个变量的内存布局分别如下:

  数组a需要在内存中占用8个字节的空间,这段内存区通过名字a来标志。指针p则需要4个字节的空间来存放地址,这4个字节用名字p来标志。其中存放的地址几乎可以指向任何地方,也可以哪里都不指,即空指针。目前这个p指向某地连续的8个字节,即字符串“Hi, pig!”。

  另外,例如:对于a[2]和p[2],二者都返回字符‘i’,但是编译器产生的执行代码却不一样。对于a[2],执行代码是从a的位置开始,向后移动2两个字节,然后取出其中的字符。对于p[2],执行代码是从p的位置取出一个地址,在其上加2,然后取出对应内存中的字符。

  问题:数组指针

  为什么在有些时候我们需要定义指向数组而不是指向数组元素的指针?如何定义?

  答案与分析:

  使用指针,目的是用来保存某个元素的地址,从而来利用指针独有的优点,那么在元素需要是数组的情况下,就理所当然要用到指向数组的指针,比如在高维需要动态生成情况下的多维数组。

  定义例子如下: int (*pElement)[2]。

  下面是一个例子:
int array[2][3] = {{1,2,3},{4,5,6}};
int (*pa)[3]; //定义一个指向数组的指针
pa = &array[0]; // '&'符号能够体现pa的含义,表示是指向数组的指针
printf ("%d", (*pa)[0]); //将打印array[0][0],即1
pa++; // 猜一猜,它指向谁?array[1]?对了!
printf ("%d", (*pa)[0]); // 将打印array[1][0],即4


  上述这个例子充分说明了数组指针—一种指向整个数组的指针的定义和使用。

  需要说明的是,按照我们在第四篇讨论过的,指针的步进是参照其所指对象的大小的,因此,pa++将整个向后移动一个数组的尺寸,而不是仅仅向后移动一个数组元素的尺寸。

  问题:指针数组

  有如下定义:
struct UT_TEST_STRUCT *pTo[2][MAX_NUM];

  请分析这个定义的意义,并尝试说明这样的定义可能有哪些好处?

  答案与分析:

  前面我们谈了数组指针,现在又提到了指针数组,两者形式很相似,那么,如何区分两者的定义呢?分析如下:

  数组指针是:指向数组的指针,比如 int (*pA)[5]。

  指针数组是:指针构成的数组,比如int *pA[5]。

  至于上述指针数组的好处,大致有如下两个很普遍的原因:

  a)、各个指针内容可以按需要动态生成,避免了空间浪费。

  b)、各个指针呈数组形式排列,索引起来非常方便。

  在实际编程中,选择使用指针数组大多都是想要获得如上两个好处。

问题:指向指针的指针

  在做一个文本处理程序的时候,有这样一个问题:什么样的数据结构适合于按行存储文本?

  答案与分析:

  首先,我们来分析文本的特点,文本的主要特征是具有很强的动态性,一行文本的字符个数或多或少不确定,整个文本所拥有的文本行数也是不确定的。这样的特征决定了用固定的二维数组存放文本行必然限制多多,缺乏灵活性。这种场合,使用指向指针的指针有很大的优越性。

  现实中我们尝试用动态二维数组(本质就是指向指针的指针)来解决此问题:

  图示是一个指针数组。所谓动态性指横向(对应每行文本的字符个数)和纵向(对应整个文本的行数)两个方向都可以变化。

  就横向而言,因为指针的灵活性,它可以指向随意大小的字符数组,实现了横向动态性。

  就竖向而言,可以动态生成及扩展需要的指针数组的大小。

  下面的代码演示了这种动态数组的用途:
// 用于从文件中读取以 '/0'结尾的字符串的函数
extern char *getline(FILE *pFile);
FILE *pFile;
char **ppText = NULL; // 二维动态数组指针
char *pCurrText = NULL; // 指向当前输入字符串的指针
ULONG ulCurrLines = 0;
ULONG ulAllocedLines = 0;

while (p = getline(pFile))
{
 if (ulCurrLines >= ulAllocedLines)
 {
  // * 当前竖向空间已经不够了,通过realloc对其进行扩展。
  ulAllocedLines += 50; // 每次扩展50行。
  ppText = realloc (ppText, ulAllocedLines * (char *));
  if (NULL == ppText)
  {
   return; // 内存分配失败,返回
  }
 }
 ppText[ulCurrLines++] = p; // 横向“扩展”,指向不定长字符串
}


  问题:指针数组与数组指针与指向指针的指针

  指针和数组分别有如下的特征:

  指针:动态分配,初始空间小

  数组:索引方便,初始空间大

  下面使用高维数组来说明指针数组、数组指针、指向指针的指针各自的适合场合。

   多维静态数组:各维均确定,适用于整体空间需求不大的场合,此结构可方便索引,例a[10][40]。

   数组指针:低维确定,高维需要动态生成的场合,例a[x][40]。

   指针数组:高维确定,低维需要动态生成的场合,例a[10][y]。

   指向指针的指针:高、低维均需要动态生成的场合,例a[x][y]。

  问题:数组名相关问题

  假设有一个整数数组a,a和&a的区别是什么?

  答案与分析:

  a == &a == &a[0],数组名a不占用存储空间。需要引用数组(非字符串)首地址的地方,我一般使用&a[0],使用a容易和指针混淆,使用&a容易和非指针变量混淆。

  区别在于二者的类型。对数组a的直接引用将产生一个指向数组第一个元素的指针,而&a的结果则产生一个指向全部数组的指针。例如:
int a[2] = {1, 2};
int *p = 0;
p = a; /* p指向a[0]所在的地方 */
x = *p; /* x = a[0] = 1*/
p = &a; /* 编译器会提示你错误,*/
/*显示整数指针与整数数组指针不一样 */


  问题:函数指针与指针函数
 
  请问:如下定义是什么意思:
int *pF1();
int (*pF2)();


  答案与分析:

  首先清楚它们的定义:

   指针函数,返回一个指针的函数。

   函数指针,指向一个函数的指针。

  可知:

   pF1是一个指针函数,它返回一个指向int型数据的指针。

   pF2是一个函数指针,它指向一个参数为空的函数,这个函数返回一个整数。

http://www.jys.cdut.edu.cn/clanguage/clanguagegeneral/ziy/fudaozl/Cerr.htm

C源程序常见错误分析
 

一、C语言出错有两种情况:

1、语法错误。指编程时违背了C语法的规定,对这类错误,编译程序一般都能够给出“出错信息”,并且告诉在哪一行出错及出错的类型。只要仔细检查,是可以很快发现错误并排除的。

2、逻辑错误。程序并无违背语法规则,但程序执行结果与原意不符。这是由于程序设计人员写出的源程序与设计人员的本意不相同,即出现了逻辑上的混乱。

例如:

unsigned char i=1;

unsigned int sum=0;

while (i<=100)

sum=sum+i;

i++;

在上例中,设计者本意是想求从1到100的整数和,但是由于循环语句中漏掉了大括号,使循环变为死循环而不是求累加。对于这种错误,C编译通常都不会有出错信息(因为符合C语法,但有部分编译系统会提示有一个死循环)。对于这类逻辑错误,比语法错误更难查找,要求程序设计者有丰富的设计经验(不会有类似的错误)和有丰富的排错经验(通过仿真能够很快发现问题)。

二、初学者在编写C源程序时常见错误及分析

1、忘记定义变量就使用

例如:

main ()

{

x=3;

y=x;

}

在上式中看似正确,实际上却没有定义变量x和y的类型。C语言规定,所有的变量必须先定义,后使用。因此在函数开头必须有定义变量x和y的语句,应改为:

main ()

{

int x,y;

x=3;

y=x;

}

2、变量没有赋值初就直接使用。(似乎编译时不会自动初始化,没有赋值时会是产生一个不确定的值,全局变量除会自动初始化)

例如:

unsigned int addition (unsigned int n)

{

unsigned int i;

unsigned int sum;

for (i=0;i<n;i++)

sum+=i;

return (sum);

}

上例中本意是计算1到n之间整数的累加和,但是由于sum没有赋初值,sum中的值是不确定的,因此得不到正确的结果。应改为如下:

unsigned int addition (unsigned int n)

{

unsigned int i;

unsigned int sum=0;

for (i=0;i<n;i++)

sum+=i;

return (sum);

}

或者将sum定义为全局变量(全局变量在初始化时自动赋值“0”)。

unsigned int sum;

unsigned int addition (unsigned int n)

{

unsigned int i;

for (i=0;i<n;i++)

sum+=i;

return (sum);

}

3、输入输出的数据类型与所用格式说明符不一致

例如:

main ( )

{

int a=3,b=4.5;

printf("%f %d/n",a,b);

}

在上例中,a与b变量错位,但编译时并不给出出错信息,输出结果为:

0.000000 16402

它们并不是按赋值的规则进行转换,如把3转换成3.0,把4.5转换成4,而是将存储单元中的数据按格式符的要求的宽度直接输出,如b占4个字节却用“%d”说明,则只有最后两个字节中的数据当成一个整数输出,a也相同,将a地址前两个字节(并不属于a)与变量a的两个字节当成一个4个字节的浮点数输出。

4、没有注意数据的数值范围

8位单片机适用的C编译器,对字符型变量分配一个字节,对整型变量分配二个字节,因此有数值范围的问题。有符号的字符变量的数值范围为-128~127,有符号的整型变量的数值范围为-32768~32767。其它类型变量的范围这里就不再一一列举,请读者参见相应编译器的使用手册。

例如:

main ()

{

char x;

x=300;

}

在上例中,有很多读者会认为x的值就是300,实际上却是错误的。

300的二进制为0b100101100,赋值给x时,将赋值最后的8位,高位截去,因此x的值实际上为0b101100(即整数44)。

如果将500赋给一个有符号的字符型变量时,变量内存储的值还会变成负数,由读者自行分析原因。

5、输入变量时忘记使用地址符号

常见是忘记使用地址符:

例如:

main ()

{

int a,b;

scanf ("%d%d",a,b);

}

应改为:

scanf ("%d%d",&a,&b);

6、输入时数组的组织方式与要求不符

scanf ("%d %d",a,b);

如果输入数据格式为:

3,4

则是错误的,两个数据之间应用空格分来分隔,应为:

3 4

7、误把“=”作为关系运算符“等于”

在数学和其它高级语言中,都是把“=”作为关系运算符“等于”,因此容易将程序误写为:

if (a=b)

c=0;

else

c=1;

在上例中,本意是如果a等于b,则c=0,否则c=1。但C编译系统却认为将b赋值给a,并且如果a不等于0,则c=0,当a等于0,则c=1,这与原设计的意图完全不同。应将条件表过式更改为:

a==b

8、语句后面漏加分号

C语言规定语句末尾必须有分号,分号是C语句不可缺少的一部分,

例如:

main ()

{

unsigned int i,sum;

sum=0;

for (i=0;i<10;i++)

{sum+=i}

}

很多初学者认为用大括号括起就不必加分号,这是错误的,即使该语句用大括号括起来,也必须加入分号。在复合语句中,初学者往往容易漏写最后一个分号。上例应改为如下形式:

main ()

{

unsigned int i,sum;

sum=0;

for (i=0;i<10;i++)

{sum+=i;}

}

当漏写分号而出错,光标将停留在漏写分号的下一行。

9、在不该加分号的地方加了分号

#include "io8515v.h";

由于伪指令不是C程序语句,因此后面不能加分号。

初学者也常在判断语句的条件表达式后面加入分号,

例如:

main ()

{

unsigned int i,sum;

sum=0;

for (i=0;i<10;i++);

sum+=i;

}

在上例中,在for的表达式后面中入分号,则C编译认为循环体是一个空操作,这与设计者的本意不符。

10、对应该有花括号的复合语句,忘记加花括号

例如:

unsigned char i=1;

unsigned int sum=0;

while (i<=100)

sum=sum+i;

i++;

我们在前面举过这个例子,应改为:

unsigned char i=1;

unsigned int sum=0;

while (i<=100)

{

sum=sum+i;

i++;

}

11、括号不配对

当一个复合语句中使用多层括号时,常会出现这类错误;也常出现大括号不配对的现象,都是粗心所致。

例如:

while ((c=getchar ()!='a')

putchar(c);

少了一个右括号。

12、没有注意大写字母和小写字母代表不同的标识符

例如:

main ()

{

int a,b,c;

a=0;

B=1;

C=a+B;

}

在上例中,C编译系统会提示变量B、C没有定义。应改为:

main ()

{

int a,B,C;

a=0;

B=1;

C=a+B;

}

13、引用数组元素时误用圆括号

main ()

{

int i,a[10];

for (i=0;i<10;i++)

scanf ("%d",a(i));

}

通常情况下,C程序编译出错,但是如果恰好有一个函数a(),则通常情况都可以通过编译,那查起错误来就更麻烦了。

14、引用数组元素超界

例如:

main ()

{

int i,a[5]={1,2,3,4,5};

for (i=1;i<=5;i++)

printf ("%d",a[i]);

}

上例中,本意是想输出数组a的全部元素,实际上,定义的数组a[5]中,只有a[0]~a[4],5个元素,并不存在a[5]。应改为如下形式:

main ()

{

int i;

int a[5]={1,2,3,4,5};

for (i=0;i<5;i++)

printf ("%d",a[i]);

}

15、对二维或多维数组定义和引用的方式不对

例如:

main ()

{

int a[5,4],

/* 其它程序 */

}

在C语中,对二维数组和多维数组在定义和引用时必须将每一维数组中的数据分别用方括号括起来,因此定义一个二维数组,应改为:

int a[5][4];

16、误以为数组名代表整个数组

例如:

main ()

{

int a[5]={1,2,3,4,5};

printf ("%d,%d,%d,%d,%d",a);

}

在上例中,本意是输出数组a中的全部元素,但是数组名a却只是代表数组的首地址,并不能代表数组中的所有元素,因此并不能得到所需的结果,应改为:

main ()

{

int a[5]={1,2,3,4,5};

printf ("%d,%d,%d,%d,%d",a[0],a[1],a[2],a[3],a[4]);

}

17、混淆字符数组与字符指针的区别

例如:

main ()

{

char str[10];

str="ICCAVR";

printf ("%s/n",str);

}

在上例中,编译必定出错。因为str[10]是一个数组,str代表数组名,是一个常量,不能被赋值,可将str改为指针变量,将字符串"ICCAVR"的首地址赋值给指针变量str,然后在Printf函数中输出字符串。如下:

main ()

{

char *str;

str="ICCAVR";

printf ("%s/n",str);

}

如果坚持要使用数组,一种方式为初始化时赋值,另一种只能在程序中一个一个元素进行赋值。分别如下:

main ()

{

char str[10]="ICCAVR";

printf ("%s/n",str);

}

main ()

{

char str[10];

str[0]='I';str[1]='C';str[2]='C';str[3]='A';str[4]='V';

str[5]='R';str[6]='/0';str[7]='/0';str[8]='/0';str[9]='/0';

printf ("%s/n",str);

}

要注意:

char str[10]="ICCAVR";

char str[10];

str="ICCAVR";

是不相同的。

18、在引用指针变量之前没有对它赋值

main ()

{

char *p;

scanf ("%s",p);

/* 用户程序 */

}

没有给指针变量赋值就使用它,由于指针变量p的值不确定,因此有可能误指向有用的存储空间,导致程序运行出错。应当改为:

main ()

{

char *p,str[20];

p=str;

scanf ("%s",p);

/* 用户程序 */

}

19、switch语句的各分支漏写了break语句

例如:

switch (time)

{

case 0 : a=0;

case 1 : a=0;

case 2 : a=2;

defult : a=3;

}

上例中,本意是根据time的值来决定a的值,但是最后程序执行的结果都一样(a=3),因为漏写了break语句,程序将从相应的case开始顺序执行,应改为:

switch (time)

{

case 0 : a=0; break;

case 1 : a=0; break;

case 2 : a=2; break;

defult : a=3;

}

20、混淆了字符和字符串的表示形式

例如:

char sex;

sex="M";

由于sex是字符变量,只能存放一个字符,用单引号括起来的是字符常量,才能赋值给一个字符型变量,而用双引号括起来的是字符串常量,它包括两个字符“M”和“/0”,无法存放到字符变量中。应改为:

char sex;

sex='M'

21、使用自加(++)和自减(--)时出错

例如:

main ()

{

int *p,a[5]={0,1,2,3,4};

p=a

printf ("%d",*p++);

}

在上例中,“*p++”本意是指p加1,即指向第1个元素a[1]外,然后输出第一个元素a[1]的值1。但实际上是先执行p++,先使用p的原值,使用后再加1,因此实际执行结果是输出a[0]的值。应改为如下:

main ()

{

int *p,a[5]={0,1,2,3,4};

p=a;

printf ("%d",*(++p));

}

说明:要注意区别p++、*p++、*(++p)和(*p)++的区别,详见“2.7.4 数组的指针和指向数组的指针变量”一节的介绍。

22、所调用的函数在调用语句之后定义,但在调用之前没有说明

例如:

main ()

{

float x=2.0,y=6.0,z;

z=max(x,y);

printf ("%f",z);

}

float max (float x,float y)

{

return (z=x>y ? x:y)

}

在上例的程序中,max函数在main函数之后定义,在调用之前又没有说明,因此出错。应在调用前对函数进行说明:

main ()

{

float max (float x,float y);

float x=2.0,y=6.0,z;

z=max(x,y);

printf ("%f",z);

}

float max (float x,float y)

{

return (x>y ? x:y);

}

也可以将函数max在函数main之前定义。

23、误认为形参值的改变会影响实参的值

例如:

main ()

{

int x=3,y=4;

swap(x,y);

printf ("%d,%d",x,y);

}

int swap (int x,int y)

{

int z;

z=x;x=y;y=z;

}

在上例中,设计者的意图本想是利用swap函数交换x和y的值,但是由于实参和形参之间单向传递,在函数swap中改变了x和y值,main中的x和y是不会改变的。可以改为使用指针的形式,如下:

main ()

{

int x=3,y=4;

int *p1,*p2;

p1=&x ; p2=&y;

swap(p1,p2);

printf ("%d,%d",x,y);

}

int swap (int *p1,int *p2)

{

int z;

z=*p1;*p1=*p2;*p2=z;

}

说明:虽然函数swap在调用函数之后定义,而且在函数main调用之前又没有说明,但是由于swap返回值为整型,C语言规则返回值为整形的函数在调用之前可以不必说明,因此本例中是符合C语法规定的。

24、函数的实参和形参类型不致。

还是使用上例:

main ()

{

int x=3,y=4;

int *p1,*p2;

p1=&x ; p2=&y;

swap(p1,p2);

printf ("%d,%d",x,y);

}

int swap (int p1,int p2)

{

int z;

z=p1;p1=p2;p2=z;

}

C要求实参与形参的类型一致,一个为指向整型变量的指针,另一个为整型变量,类型不同,因此编译出错。

25、不同类型的指针混用

例如:

main ()

{

char x=3,*p1;

int *p2;

p1=&x;

p2=p1;

printf ("%d,%d",x,y);

}

在上例中,设计者本意是想将指针p1所指的值赋p2,但是由于p1与p2所指向的类型不同,不能赋值。在赋值时必须进行强制类型转换。如:

main ()

{

char x=3,*p1;

int *p2;

p1=&x;

p2=(int *)p1;

printf ("%d,%d",*p1,*p2);

}

指向不同类型的指针变量进行强制转换后赋值,在C中是常用的,例如,用malloc函数开辟的数据存储单元,函数的返回值是一个空指针(void),需要用强制转换成指向所需存储类型,如指向一个结构体,用以组成一个链表:

struct str

{

int a;

struct str *next;

}*p1;

/* 用户程序列 */

p1=(struct str *)malloc (size_t,size)

在ICCAVR中,malloc函数返回的是void类型的指针,将其强制转换为struct str类型的结构体指针。

26、混淆数组与指针变量的区别

例如:

main ()

{

int i,a[5];

for (i=0;i<5;i++)

scanf ("%d",a++);

}

在上例中,设计者意图通过a++的操作,引用a数组的不同元素。由于C规定数组名代表数组的首地址,它的值是一个常量,因此用a++是错误的。应改为用指针变量来实现,如:

main ()

{

int i,a[5],*p;

p=a;

for (i=0;i<5;i++)

scanf ("%d",p++);

}

或:

main ()

{

int a[5],*p;

for (p=a;p<a+5;p++)

scanf ("%d",p);

}

27、混淆结构体类型与结构体变量的区别

例如:

struct worker

{

unsigned char num;

char name[20];

};

worker.num=1;

在上例中,只是说明了一种struct worker的结构,但是C编译器并没有为这种类型的结构体变量开辟存储空间,因此不能对结构体类型赋值。应用该类型定义了一个结体类型的变量后,才能对这个变量赋值,应改为:

struct worker

{

unsigned char num;

char name[20];

};

struct worker work;

work.num=1;

http://zhhui.blogchina.com/221785.html

VC编译常见错误- -

1、Fatal Error C1010
unexpected end of file while looking for precompiled header directive
这一般是由于使用了参数/Yu"stdafx.h",意思是在每个文件中都应该使用#include来包含这个头文件。一般改正,就是在每个。CPP文件中包含这个文件就可以。
2、LNK2001 on __beginthreadex and __endthreadex
这是一个非常常见的链接错误。原因是由于在VC3。0以后所有的MFC类都是线程安全的,在MFC类库中使用了Thread Local Storage (TLS)提供预处理的数据。因此如果程序中包含了"stfafx.h"头文件或者使用了,MFC类库中的类就会使用MSVCRTx0.DLL 来进行链接。改正方法如下:
On Visual C 2.x, 5.0, and 6.0:
Select the Project menu, and then continue Steps 2 through 5 below.
On Visual C 4.x:
Select the Build menu.
Select the Settings... option.
Select the C/C++ tab.
Select Code Generation on the Category list box.
Finally, make a selection other than Single-Threaded on the Use Run Time Library list box.
如果使用了"Multithreaded using DLL"方式还要求在预处理符号中加上_AFXDLL 符号.
还在LIBC。LIB是C Runtime的静态链接库。
MSVCRTx0.DLL 是C Runtime的动态链接库。
如果程序中包含了任何MFC代码,或者编译使用了/MT选项,都要求使用多线程库。
为什么在程序中包含了"StdAfx.h"文件也会出现这个连接错误呢?是由于在"StdAfx.h"中使用了MFC类,并且重载了new等操作符,如果在程序中使用了NEW等就会出现链接错误。

1、Fatal Error C1010
unexpected end of file while looking for precompiled header directive
这一般是由于使用了参数/Yu"stdafx.h",意思是在每个文件中都应该使用#include来包含这个头文件。一般改正,就是在每个。CPP文件中包含这个文件就可以。
2、LNK2001 on __beginthreadex and __endthreadex
这是一个非常常见的链接错误。原因是由于在VC3。0以后所有的MFC类都是线程安全的,在MFC类库中使用了Thread Local Storage (TLS)提供预处理的数据。因此如果程序中包含了"stfafx.h"头文件或者使用了,MFC类库中的类就会使用MSVCRTx0.DLL 来进行链接。改正方法如下:
On Visual C 2.x, 5.0, and 6.0:
Select the Project menu, and then continue Steps 2 through 5 below.
On Visual C 4.x:
Select the Build menu.
Select the Settings... option.
Select the C/C++ tab.
Select Code Generation on the Category list box.
Finally, make a selection other than Single-Threaded on the Use Run Time Library list box.
如果使用了"Multithreaded using DLL"方式还要求在预处理符号中加上_AFXDLL 符号.
还在LIBC。LIB是C Runtime的静态链接库。
MSVCRTx0.DLL 是C Runtime的动态链接库。
如果程序中包含了任何MFC代码,或者编译使用了/MT选项,都要求使用多线程库。
为什么在程序中包含了"StdAfx.h"文件也会出现这个连接错误呢?是由于在"StdAfx.h"中使用了MFC类,并且重载了new等操作符,如果在程序中使用了NEW等就会出现链接错误。

http://www.blog.edu.cn/user2/shuquanying/archives/2006/1327664.shtml

Visual C++ Error Messages

Visual C++ Error Messages

This page contains a listing of "difficult to diagnose" error messages and possible fixes. I haven't taught a programming class that uses Visual C++ in several years so this list is probably out of date by now. It was valid for Microsoft Visual C++ version 6.0 service pack 3.

C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1786) Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more information

This error results from leaving off the parentheses immediately following the function name in a function header. To correct the error simply add () to the end of the function name.

C1010: unexpected end of file while looking for precompiled header directive

If your project is an MFC AppWizard created project then this error results from not #including StdAfx.h as the first #i nclude statement (before any other #i ncludes, data declarations, or executable program code).

C1083: Cannot open precompiled header file: 'Debug/<Project-Name>.pch': No such file or directory

This error results from a missing file - the compiled version of StdAfx.cpp. Visual C++ does a poor job of keeping track of this file and frequently "forgets" how to build it. This problem often occurs after restoring a saved workspace from diskette without the Debug directory. To fix the error select StdAfx.cpp from the workspace file list them choose Compile from the Build menu. If that doesn't work the go to Project -> Settings, select the C/C++ tab, and click the radio button labeled Create Precompiled Headers.

C2001: newline in constant

This error is usually caused by a string or character constant that is missing its closing ' or " symbol.

C2065: '<data-member name>' : undeclared identifier

If this error occurs in one of your member functions then it is generally the result of forgetting the class scope operator in front of the function name in your .cpp file.

C2143: syntax error : missing ';' before 'PCH creation point'

Check each of the #i nclude files to ensure that the closing brace of each class declaration is followed by a semicolon.


C2143: syntax error : missing ';' before '*'

If this error is followed by two C2501 errors then the problem is an undeclared class name within a pointer declaration.

For example, the declaration:

CClass *pObject;

will generate the above error message followed by a C2501 error message for 'CClass' and another C2501 message for 'pObject'. The problem is that the compiler isn't recognizing CClass as a valid class/type name. To correct the problem add a #i nclude of the file containing the declaration of CClass (e.g., #i nclude CClass.h)

C2447: missing function header (old-style formal list?)

This error usually results from a missing { or use of a ; instead of a { following the parameter list of a function header.

C2511: '<function-name>' : overloaded member function not found in '<class-name>'

This error results from a mismatch in the parameter list of a member function declaration (.h file) and definition (.ccp file). Check the forward declaration of the function in the .h file and its definition in the .cpp file and ensure that the number of parameters and the type of each parameter match exactly.

C2512: '<constructor-function-name>' : no appropriate default constructor available

This error usually occurs when you implement the constructor function of a derived class and forget to include parameter passing to the base class constructor function. For example assume that CDerived is derived from CBase and that the CBase constructor function requires one parameter (e.g., int A). If you define the CDerived constructor function as:

CDerived::CDerived(int A, int B) { ... }

the compiler will issue the above error message on the line containing the function header of CDerived::CDerived() because you haven't provided instructions for routing the parameter A to CBase::CBase(). Because you didn't provide instructions the compiler assumes that CBase::CBase() requires no arguments and it complains because no version of CBase::CBase() has been defined that accepts zero arguments.

If you intended to provide a version of CBase::CBase() that requires no arguments then the error message indicates that you forgot to declare that function in your base class declaration (e.g., in CBase.h).

If CBase::CBase() does require one or more arguments then you must correct the problem by including explicit instructions for passing parameters from the derived class constructor function to the base class constructor function. The correction for the example above is:

CDerived::CDerived(int A, int B) : CBase(A) { ... }

C2556: '<function-name>' : overloaded functions only differ by return type
C2371: '<function-name>' : redefinition; different basic types

These errors usually result from a mismatch of function type between a .h and .cpp file. Check the forward declaration of the function in the .h file and its definition in the .cpp file and make the function return type identical in both files.

C2601: '<function-name>' : local function definitions are illegal

This error results from defining one function inside the body of another function. It usually means that you omitted one or more } symbols in the function just before the function named in the error message.

C2653: '<Class-Name>' : is not a class or namespace name

This error usually results from not having #i nclude "StdAfx.h" as the first #i nclude statement in your class.cpp file. It can also occur if your class definition is in a .h file and you forget to #i nclude that .h file in another file that refers to the class name.

C2661: '<Class-Name>::<Function-Name>' : no overloaded function takes n parameters

This error indicates a mismatch between the parameters used in a function call (e.g., from main.cpp) and the declaration of the function. The function call is passing n parameters and there is no function declaration that uses that number of parameters.

LNK1104: Cannot open file nafxcwd.lib

This error sometimes occurs when a project uses a class from the MFC but the project settings don't explicitly tell the link editor to look in the MFC libraries.

Go to Project --> Settings (Build --> Settings in Visual C++ 4.0). On the General tab check the box that says "Use MFC in a Shared DLL".

LNK1168: cannot open Debug/<Project-Name>.exe for writing

This error occurs when the link editor attempts to write to a .exe file that is currently in use. The .exe file of an executing program is write protected until the program is terminated. Look at the status bar at the bottom of your screen and find the icon representing your executable application. Open the application and exit from it. Then select Build.

LNK2001: unresolved external symbol __endthreadex
LNK2001: unresolved external symbol __beginthreadex

These errors result from using an MFC object or function without telling the link editor to search the MFC libraries.

Go to Project --> Settings (Build --> Settings in Visual C++ 4.0). On the General tab check the box that says "Use MFC in a Shared DLL".

LNK2001: unresolved external symbol _main

Your project doesn't contain a function called main(). The error usually results from forgeting to add main.cpp to the project workspace.

<File>.obj : error LNK2001: unresolved external symbol "public: void __thiscall <Class1>::<Function1>(<Type>)"

This a generic form of a LNK2001 error where <File>.obj can be any object file in your project and <Class1>::<Function1>(<Type>) can be any function in any class. Substitute the specific <File>, <Class>, <Function>, and <Type> in your message into the instructions below to diagnose and correct the problem.

An LNK2001 error means that the link editor is looking for a compiled function and can't find it. The call to the "missing function" is somewhere in <File>.cpp. Unfortunately, double-clicking on the error message won't take you to the point in <File.cpp> where the function is called but you can search for it with Find or Find In Files. The function the link editor can't find is a member of <Class>, its name is <Function1>, and its return type is <Type>.

There are two common reasons for a LNK2001 error:
The call in <File>.cpp doesn't match the function prototype in <Class>.h and/or the implementation in <Class>.cpp. The mismatch may be in the function name, return type, or number and/or type of parameters. Correction strategies include:
Check that the function name is spelled the same (case sensitive) in all three files (File.cpp, Class.h, and Class.cpp).
Check that the function is actually declared and defined within <Class> - perhaps you defined it as a member of a different class or perhaps you tried to call the function (in <File>.cpp) using an object or object pointer of a different class.
Check that the number and type of parameters in the function implementation (in <Class>.cpp) matches the number and type of parameters declared in the function declaration in <Class>.h.
Check that the number and type of parameters in the function call (in <File>.cpp) matches the number and type of parameters declared in the function header in <Class>.cpp.
The function was never declared or was declared but never defined. To see if either is the case go to the ClassView window of the Workspace view. Click the + next to <Class> and find <Function> in the list of member functions.
If <Function> is NOT in the list then it was never declared or defined - add a declaration to the class declaraion in <Class>.h and implement the function in <Class>.cpp.
If <Function> is in the list then right click on it and select Go To Definition from the pop-up menu. If you get the error message Cannot find definition (implementation) of this function then the function was declared but never defined (implemented). Implement the function to <Class>.cpp.

LNK2005: <some-long-string-of-mostly-garbage> already defined in <name>.lib(<name>.obj)

This error usually results from including a source code file multiple times. If you recognize any of the names in the message then it probably results from multiple inclusion of one of your own header files. Check to be sure that you've used #ifndef/#define/#endif properly your header files. If you don't recognize the name then it's probably multiple inclusion of a system file (e.g., afxwin.h). Make sure that you haven't explicitly included something in main.cpp that is already included in one of your own header files. Also check that you haven't #i ncluded a .cpp file where you should have #i ncluded a .h file.

http://yinqing.blog.hexun.com/5383739_d.html

作 者:happyparrot 出处:[url]http://community.csdn.net/Expert/topic/4258/4258967.xml?temp=.1825373[/url]

1. Linking...
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
libcd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main

Q:

VC++默认的工程设置是单线程的,而你使用了多线程,所以要修改设置。选择菜单“Project|settings”,选择C/C++标签,在CODE GENERATION分类中选择除SINGLE-THREADED的其他选择。

2.fatal error C1010: unexpected end of file while looking for precompiled header directive

Q:
两个办法:
-->肯定是一个新添加的类的.cpp文件开头没包含stdafx.h,在该文件最前面加上即可
-->有时可以使用右键点击项目工程中的该cpp文件,选择setting,在c/c++栏,选择PreCompiled headers,然后设置第一选项,选择不使用预编译头,解决这个问题。

3.在编译时产生的下面的代码,那么下面的代码中的括号内的数字代表什么意思,还有error后的数字呢?
Compiling...
CalWnd.cpp
E:/StudyVC/CalendarApp/CalWnd.cpp(1092) : error C2065: 'TTS_BALLOON' : undeclared identifier
E:/StudyVC/CalendarApp/CalWnd.cpp(1092) : error C2059: syntax error : ')'
E:/StudyVC/CalendarApp/CalWnd.cpp(1092) : warning C4552: '|' : operator has no effect; expected

operator with side-effect
Error executing cl.exe.

Q:括号中的数字是出错的代码行的行号。例如错误中的第1行表示CalWnd.cpp的1092行出现了错误。如果想快速找到这行,可以在错误信息行上双击鼠标,这时VC++会自动打开CalWnd.cpp文件并定位到这行。
Error后面的数字表示错误代号。错误代号分为两类:C开头的是编译错误,即你的代码存在语法错误,你需要修改代码;LNK开头的是链接错误,通常你的代码并没有语法错误,可能是配置错误引起的,但有时LNK可能是由于拼写错误引起的。在错误信息行上按F1键,VC++会打开MSDN帮助并显示关于该错误信息的一个简单的解释,你可以根据该解释来知道到底是什么意思。

4.vc编译的时候可以设置两个版本:debug和release,debug版本在运行的时候点击帮助菜单的about对话框出现如下错误信息:
Debug Assertion Failed:
Program :C:/fuan/Debug/fuan.exe
File:wincore.cpp
Line:628

For information on how your program can cause an assertion failure,see visual c++ documentation on asserts.
(Please retry to debug application).
但是如果把配置改成release版本,就不会出现问题,about对话框弹出正常。使用的是同一个源程序,为什么会出现不同的结果?

Q:
在MFC中,大量使用了ASSERT宏,这些宏通常可以来纠正一些错误,如还没有初始化指针就使用等。你所遇到的信息就是ASSERT宏报告的错误。通常你要检查一下是否存在错误。在Release方法下,ASSERT宏不会执行,所以也没有错误信息。不过,MFC中的ASSERT宏有时管得有点宽,如果确认没有错误,也可以不理会它。

5. 在win2000上能编译的程序到了win98就不能编译了。
没有出错信息,一编译就停在
--Configuration: Monitor - Win32 Release-------
Copying contents file...
是不是跟*.hpj文件有关系,应该怎么改?

Q:是和编译帮助文件有关,据说如果在Win98下安装了Norton AntiVirtus 2000就会出现这种问题。可以把帮助文件从工程中去掉:
1、在FileView标签下,选择Source Files文件夹下面的.hpj文件。
2、右击文件并从菜单中选择Settings。
3、点击General标签。
4、清除掉Always use custom build step选项并选择Exclude file from build。

6.在用EnumWindows(EnumWindowsProc,(LPARAM)0);编译时老是出错:cannot convert parameter 1 from 'int (struct HWND__ *,long)' to 'int (__stdcall *)(struct HWND__ *,long)'

Q:实际上看一下错误信息就知道,你的EnumWindowsProc大概定义为:
int EnumWindowsProc(HWND, long);

实际应该定义为:
int __stdcall EnumWindowsProc(HWND, long);

7.编译以WinMain开头的函数出现LNK2001错误
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/Cpp1.exe : fatal error LNK1120: 1 unresolved externals
Q:估计是选错了工程类型。在VC中除了可以编译MFC程序外,还可以建立Win32 Application,以WinMain为主函数。可以在VC中建立Win32 Application,然后加入你的C程序,然后编译即可。

8.编译后出现大量错误信息怎么办
错误信息如下:
Info :Compiling C:/user/x.cpp
Error: x.cpp(20,26):Call to undefined function 'loadCursor'
Error: x.cpp(20,15):Cannot convert 'int' to 'HICON__ *'
Error: x.cpp(23,21):Cannot convert 'void *' to 'HBRUSH__ *'
Error: x.cpp(30,6):Undefined symbol 'hWnd'
Error: x.cpp(32,13):Cannot convert 'void *' to 'HINSTANCE__ *'
Error: x.cpp(32,13):Type mismatch in parameter 'hInstance' in call to
'__stdcall CreateWindowExA(unsigned long,const char *,const char
*,unsigned long,int,int,int,int,HWND__ *,HMENU__ *,HINSTANCE__ *,void
*)'
Error: x.cpp(33,32):Undefined symbol 'SHOW_MAXIMIZED'
Warn : x.cpp(40,2):'hwnd' is declared but never used
Warn : x.cpp(40,2):Parameter 'lpszCmdLine' is never used
Warn : x.cpp(40,2):Parameter 'nCmdShow' is never used
Error: x.cpp(54,20):Illegal structure operation
Error: x.cpp(54,41):Undefined symbol 'tmExternalLeading'
Error: x.cpp(56,40):Undefined symbol 'poshorzscoll'
Error: x.cpp(57,40):Undefined symbol 'posvertscoll'
Error: x.cpp(58,16):Call to undefined function 'SetSCrollRange'
Error: x.cpp(135,73):Function call missing )
Error: x.cpp(142,7):Misplaced break
Error: x.cpp(143,5):Case outside of switch
Error: x.cpp(143,17):Expression syntax
Error: x.cpp(145,7):Misplaced break
Error: x.cpp(146,8):Default outside of switch
Warn : x.cpp(148,2):'slength' is declared but never used
Error: x.cpp(149,7):Declaration terminated incorrectly
Error: x.cpp(150,2):Unexpected }

Q:不可能一一为你分析错误,告诉你一些消除错误的原则,你自己来逐一分析,这样你才能学会编程。
首先,用不着见到错误就六神无主。错误信息虽多,但没什么了不起。编译错误就象是拼写检查的结果。
下面,看看有多少条错误信息(Error)和警告(Warn)。当然先分析错误信息,有些警告是由于错误信息产生的。如果你对某条错误信息的含义不了解,可以选择该条错误信息,然后按F1键,在帮助文件中肯定会有更详细的介绍。
绝大多数编译错误实际上都是拼写错误。看看你的程序吧。凡是undefined错误都是拼写错误。象把LoadCursor写成loadCursor,hWnd写成hwnd,别忘了C/C++是区分大小写的!还有把SW_SHOWMAXIMIZED写成SHOW_MAXIMIZED。有时候记忆出了错误,查查手册或帮助就行了。
接下来,要查“(”、“)”、“{”、“}”等各种括号的匹配问题。Function call missing )、Misplaced break、Case outside of switch这些信息都说明你的程序中存在匹配问题。你的程序中有一行 TextOut(hdc,-charwt*(poshorzscroll,charht*(t-posvertscroll),szbuffer,i);} 显然少了一个“)”括号。一般在检查这种错误时,必须找到第一个出现此类错误的地方,修改后一般立即重新

编译,因为一个匹配错误可能引发几十个错误,继续查后面的错误意义不大。
剩下的Cannot convert、Type mismatch错误是数据类型转换错误。这其实不一定是错误,因为C++对参数类型检查的要严格一些,所以有时要尽可能使用强制类型转换来避免这种错误。比如你的
wcAPP.hbrBackground=GetStockObject(WHITE_BRUSH);
导致Cannot convert 'void *' to 'HBRUSH__ *'错误,你可以试着在相关参数前加上(HBRUSH),改成
wcAPP.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
对于这类转换,不同的C++系统可能不同,所以有的时候不写也可以,但我建议要强制转换,这样麻烦少。同时要注意变量类型是否可以强制转换,比如有的参数为指针类型,要在普通变量前加“&”操作符。这要参考有关函数的帮助。

http://zhangxiaocai.spaces.live.com/blog/cns!13130e6871dda08f!129.entry

VC++常见编译错误信息
1、fatal error C1010: unexpected end of file while looking for precompiled header directive
寻找预编译头文件路径时遇到了不该遇到的文件尾。(一般是没有#include "stdafx.h")

2、fatal error C1083: Cannot open include file: 'R…….h': No such file or directory
不能打开包含文件“R…….h”:没有这样的文件或目录。

3、error C2011: 'C……': 'class' type redefinition
类“C……”重定义。

4、error C2018: unknown character '0xa3'
不认识的字符'0xa3'。(一般是汉字或中文标点符号)

5、error C2057: expected constant expression
希望是常量表达式。(一般出现在switch语句的case分支中)

6、error C2065: 'IDD_MYDIALOG' : undeclared identifier
“IDD_MYDIALOG”:未声明过的标识符。

7、error C2082: redefinition of formal parameter 'bReset'
函数参数“bReset”在函数体中重定义。

8、error C2143: syntax error: missing ':' before '{'
句法错误:“{”前缺少“;”。

9、error C2146: syntax error : missing ';' before identifier 'dc'
句法错误:在“dc”前丢了“;”。

10、error C2196: case value '69' already used
值69已经用过。(一般出现在switch语句的case分支中)

11、error C2509: 'OnTimer' : member function not declared in 'CHelloView'
成员函数“OnTimer”没有在“CHelloView”中声明。

12、error C2511: 'reset': overloaded member function 'void (int)' not found in 'B'
重载的函数“void reset(int)”在类“B”中找不到。

13、error C2555: 'B::f1': overriding virtual function differs from 'A::f1' only by return type or calling convention
类B对类A中同名函数f1的重载仅根据返回值或调用约定上的区别。

14、error C2660: 'SetTimer' : function does not take 2 parameters
“SetTimer”函数不传递2个参数。

15、warning C4035: 'f……': no return value
“f……”的return语句没有返回值。

16、warning C4553: '= =' : operator has no effect; did you intend '='?
没有效果的运算符“= =”;是否改为“=”?

17、warning C4700: local variable 'bReset' used without having been initialized
局部变量“bReset”没有初始化就使用。

18、error C4716: 'CMyApp::InitInstance' : must return a value
“CMyApp::InitInstance”函数必须返回一个值。

19、LINK : fatal error LNK1168: cannot open Debug/P1.exe for writing
连接错误:不能打开P1.exe文件,以改写内容。(一般是P1.Exe还在运行,未关闭)

20、error LNK2001: unresolved external symbol "public: virtual _ _thiscall C……::~C……(void)"
连接时发现没有实现的外部符号(变量、函数等)。

========================================================================================
在创建MFC项目时, 不使用MFC AppWizard向导, 如果没有设置好项目参数, 就会在编译时产生很多连接错误, 如error LNK2001错误, 典型的错误提示有:
libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
下面介绍解决的方法:
1. Windows子系统设置错误, 提示:
libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Windows项目要使用Windows子系统, 而不是Console, 可以这样设置:
[Project] --> [Settings] --> 选择"Link"属性页,
在Project Options中将/subsystem:console改成/subsystem:windows
2. Console子系统设置错误, 提示:
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
控制台项目要使用Console子系统, 而不是Windows, 设置:
[Project] --> [Settings] --> 选择"Link"属性页,
在Project Options中将/subsystem:windows改成/subsystem:console
3. 程序入口设置错误, 提示:
msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16
通常, MFC项目的程序入口函数是WinMain, 如果编译项目的Unicode版本, 程序入口必须改为wWinMainCRTStartup, 所以需要重新设置程序入口:
[Project] --> [Settings] --> 选择"C/C++"属性页,
在Category中选择Output,
再在Entry-point symbol中填入wWinMainCRTStartup, 即可
4. 线程运行时库设置错误, 提示:
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
这是因为MFC要使用多线程时库, 需要更改设置:
[Project] --> [Settings] --> 选择"C/C++"属性页,
在Category中选择Code Generation,
再在Use run-time library中选择Debug Multithreaded或者multithreaded
其中,
Single-Threaded 单线程静态链接库(release版本)
Multithreaded 多线程静态链接库(release版本)
multithreaded DLL 多线程动态链接库(release版本)
Debug Single-Threaded 单线程静态链接库(debug版本)
Debug Multithreaded 多线程静态链接库(debug版本)
Debug Multithreaded DLL 多线程动态链接库(debug版本)
单线程: 不需要多线程调用时, 多用在DOS环境下
多线程: 可以并发运行
静态库: 直接将库与程序Link, 可以脱离MFC库运行
动态库: 需要相应的DLL动态库, 程序才能运行
release版本: 正式发布时使用
debug版本: 调试阶段使用

分享到:
评论

相关推荐

    VC 常见编译错误

    VC,编译错误,error C2664,error C2065,error MSB8008

    C语言资料包(ASCII字符转换,C函数查询,C资料大全,C常用函数、VS&VC快捷键、C常见错误、关于指针、cmd编译C以及电子书The C Programming Language经典图书。)

    C语言资料包,里面内容包括:ASCII字符转换,C函数查询,C资料大全,C常用函数、VS&VC快捷键、C常见错误、关于指针、cmd编译C以及电子书The C Programming Language经典图书。

    vc++6.0菜单中英文对照附录常见编译错误

    1、基本包含所有的VC6.0常见错误内容及解决方法; 2、错误有中文翻译及中文解决办法指引; 3、包含基本VC6.0的快捷键操作及基本常用操作详细介绍; 4、初学C语言的同学必备的一个文档,快速上手VC6.0及C语言 5、适合...

    VC6.0错误指令及解决方法

    VC6.0 多个常见错误指令 及其解决方法

    VC 常见编译错误.pdf

    error C2065: ‘_bstr_t’ : undeclared identifier error MSB8008: 指定的平台工具集(v110)未安装或无效 error C2065: “CString”: 未声明的标识符 error C2664: “ATL::CStringT,StringTraits&gt;::Remove”: 不能...

    c及VC错误信息大全

    C以及VC++中常见错误解释及产生原因的描述,对新手比较有帮助( ⊙o⊙ )千真万确

    Visual C++常见错误及解决方案

    vc中常见的错误及解决方案,对于初学者编译和链接时常犯的错误有很大的帮助

    C语言错误提示

    C语言常见编译错误中英翻译,用于TC,VC

    VC++常见错误一览表

    1、fatal error C1010: unexpected end of file while looking for precompiled header directive。 寻找预编译头文件路径时遇到了不该遇到的文件尾。(一般是没有#include "stdafx.h") 2、fatal error C1083: ...

    VC6.0常见编译错误提示附解决方法

    (1)error C2001: newline in constant 编号:C2001直译:在常量中出现了换行。错误分析: 1.①字符串常量、字符常量中是否有换行。2.②在这句语句中,某个字符串常量的尾部是否漏掉了双引号。3.③在这语句中,某个...

    VC使用CRT调试功能来检测内存泄漏.rar_VC 内存_VC 调试_Vc_内存泄漏

    在 C/C++ 应用程序开发过程中,动态分配的内存处理不当是最常见的问题。其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不会引起我们的注意,但...

    C与C++程序设计学习与实验系统 .zip

    Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案与分析等大量的学习资源。另外 “编程...

    VC++常见安装调试错误

    VC调试常见错误 程序设计到多线程,VC++6.0默认设置可作以下修改: project-&gt;settings-&gt;C/C++-&gt;Category中选Code Generation-&gt;Use Run-time Library选Debug MultiThreaded或MultiThreaded 在创建MFC项目时, 不使用...

    Visual C++常见错误(初学者)

    使初学者能够快速找到自己的错误,省心、省力、省时。

    C_C++程序设计学习与实验系统 2010 part1

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    《C/C++程序设计学习与实验系统》

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    C与C++程序设计学习与实验系统 2011.2

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    C与C++程序设计学习与实验系统

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    C_C++程序设计学习与实验系统

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照 ...

    c/c++程序设计学习与实验系统

    Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案与分析等大量的学习资源。另外 “编程...

Global site tag (gtag.js) - Google Analytics