C、C++语言容易出错的几个地方
1. sizeof()和strlen()函数
sizeof常见标准用法(1)、(2)、(3) [摘自C++ Reference]:
//(1)
char buff[6];
strncpy(buff, argv[1], sizeof(buff));
//(2)
int array[] = { 3, 1, 4, 1, 5, 9 };
unsigned int array_size = sizeof(array) / sizeof(array[0]);
//(3)
typedef struct data_type {
int age;
char name[20];
} data;
data *bob;
bob = (data*) malloc( sizeof(data) );
if( bob != NULL ) {
bob->age = 22;
strcpy( bob->name, "Robert" );
printf( "%s is %d years old\n", bob->name, bob->age );
}
free( bob );
可见,sizeof主要用于求某种数据(例如int,数组,字符串,指针,结构体…)的size,例如:
char str[]="hello";
char *p1=str;
此时,用sizeof(str)得到的是6,因为hell0是5个字符,系统储存的时候会在hello的末尾加上结束标识\0,一共为6个字符;
而sizeof(p1)得到的却是4,它求得的是指针变量p1的长度,在32位机器上,一个地址都是32位,即4个字节。
用sizeof(*p1)得到的是1,因为*p1定义为char,相当于一个字符,所以只占一个字节。
用strlen(str),得到的会是5,因为strlen求得的长度不包括最后的\0。
用strlen(p1),得到的是5,与strlen(str)等价。
上面的是sizeof和strlen的区别,也是 指针字符串和 数组字符串 的区别。
编程时这种错误非常隐秘,见下面的一个例子。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main( )
{
char *src="hello world";
char *dest=NULL;
int len=strlen(src);//这里很容易出错,写成sizeof(src)就是求指针的长度,即4
dest=(char *)malloc(len+1);//这里很容易出错,写成len
char *d=dest;
char *s=&src[len-1]; //这里很容易出错,写成len
while(len--!=0)
*d++=*s--;
*d='\0'; //这句很容易漏写
printf("%s\n", dest);
free(dest); //这句很容易漏写
return 0;
}
注意,我上面这个C语言程序是在Linux平台下gcc编译的,Windows平台下的VC6不支持即用即声明的形式,必须先定义后使用。用VC6编译可以改成下面的形式:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main( )
{
char *src, *dest, *d, *s;
int len;
src="hello world";
dest=NULL;
len=strlen(src);
dest=(char *)malloc(len+1);
d=dest;
s=&src[len-1];
while(len--!=0)
*d++=*s--;
*d='\0';
printf("%s\n", dest);
free(dest);
return 0;
}
首先说明一下malloc函数和free函数的使用www.zzzyk.com
#include <stdlib.h>
void *malloc( unsigned int size );
它的功能是在内存的动态存储区分配一个长度为size字节的连续空间。函数返回的是一个指向分配域其实地址的指针,这个指针的类型是void类型。如果函数未能执行成功则返回一个空指针NULL,使用这个函数必须包含头文件stdio.h。
void类型的指针,指向一个类型未定的变量,也就是说它可以指向char类型变量,也可以指向int类型或其它类型。因此在将它的值赋值给另外一个指针时要进行强制类型转换,例如:
char *p1="123456";
void *p2="abcdef";
p1=(char *)p2;//两者类型必须相同,也可以p2=(void *)p1;
malloc函数必须和free函数成对出现,使用完了free(dest);
2. 数组中易错的地方
分析下面这段小程序:
#include<stdio.h>
void main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d, %d\n", *(a+1), *(ptr-1));
}
以及下面这个程序:
#include <stdlib.h>
#include <stdio.h>
static void show_str_pointer(const char **ppstr)
{
printf("%s\n", *ppstr);
}
int main()
{
char array[4] = "abc";
char *pointer = "abc";
show_str_pointer(&pointer);
show_str_pointer(&array);
return 0;
}
执行结果为:
abc
7�
&array与array的语义相同。在这里指针与数组是不能互换的。&pointer为指针的地址,与show_str_pointer参数char **ppstr指向指针的指针的变量类型相同。而&array仍然为数组地址,与参数char **ppstr的类型不符。
3. 数组的最大长度问题
int n[1000000];这样肯定是不行的,因为这样定义的数组用的是栈内存,系统默认值为最大1Mb,一个int型占4字节这样最大可以申请1024*1024/4=264144个,如果考虑到系统自身的占用最大值约为25000个。
int *p=(int *)malloc(1000000*sizeof(int));,这样用的是堆内存,只要你内存有那么多的连续空间就可以。例子如下:
#include<stdio.h>
#include<malloc.h>
int main()
{
int *p=(int *)malloc(1000000*sizeof(int));
//int p[1000000];
int i=0;
for(;i<1000000;i++)
printf("%d\n",p[i]=i);
free(p);
return 0;
}
如果非要用数组的话,一般这样写,不能再大了:
#define MAXSIZE 250000
int a[MAXSIZE];
2. fscanf和fprintf函数
将文件中的数据读出来存入指定的指针位置,例如fscanf (fp,"%d", &a[i]);
将数据存入文件中可以用fprintf函数,但是对于二进制文件,写成fprintf(fp, "%d", a[i]);就不对,因为存入的是%d格式是十进制的,所以此时不要用fprintf,换成fwrite即可。
有关二进制文件的读写参加下面一个程序:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DATASIZE 250000
int main(int argc, char ** argv)
{
const char * file_name = "out.dat";
FILE * fp = fopen(file_name, "wb");//必须放在其他变量的定义之前
int i, a, b[DATASIZE];
srand( time(NULL) );
for(i=0; i<DATASIZE; i++)
{
a=rand()%100;
fwrite(&a, sizeof(int), 1, fp);
}
fclose(fp);
fp = fopen(file_name, "rb");
fread(&b, sizeof(int), DATASIZE, fp);
补充:软件开发 , C语言 ,