user-0 提问: 用C语言读取bmp文件的像素值  结果有错误

回复:
user: user-1
content: 11楼正解！

user: user-2
content: 引用 4 楼 lwclsq 的回复:谢谢。bmp宽度为450，又因为有rgb三个分量，每行有1350个细节，而且有要是4的倍数，最后成为1352.这点没问题。 当读取少量像素值，比如30个的时候没问题，但是超过某个值的时候就出错了 你说的没错，读取少量像素的时候，没有遇到 0x0d 0x0a 序列，所以不会出错，在Windows下fopen(..., "r")这样打开文件的话， 文件里的0x0d 0x0a会被替换成0x0a的。 楼主自己试试下面这个程序就明白为啥了。  #include <stdio.h>  static int dump(char *buf, int len) { 	int i;   	printf("len=%02d: ", len); 	for (i = 0; i < len; i++) { 		printf("%02x ", (unsigned char)buf[i]); 	} 	printf("\n");  	return 0; }  int main(int argc, char *argv[]) { 	FILE *fp; 	int len; 	char buf[1024] = {0x01, 0x02, 0x0d, 0x0a, 0x03, 0x04};  	len = 6; 	dump(buf, len);  	fp = fopen("mymtom.dat", "wb"); 	fwrite(buf, 1, len, fp); 	fclose(fp);  	fp = fopen("mymtom.dat", "r"); 	len = fread(buf, 1, sizeof(buf), fp); 	fclose(fp); 	dump(buf, len);  	return 0; }  /* Windows环境下的输出: len=06: 01 02 0d 0a 03 04 len=05: 01 02 0a 03 04 */

user: user-3
content: 用开源库吧，wxWidgets之内的，有专门的封装好的图形处理函数。

user: user-4
content: 1 读写文件都加上b(rb，WB) 2 确定是24位图，直接跳过54字节，像素是连续，不需seek 3 图像处理用连续内存，一维指针足矣，每个RGB分配一次内存太浪费 4写回去不对，那个神奇数字1352忘了吧，每行要写这么多字节才行

user: user-1
content: if((fp=fopen( "d:\\1.bmp", "r"))==NULL)  和    if((fp=fopen( "d:\\1.bmp", "rb"))==NULL)  不是一回事！  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

user: user-0
content: for(i=0;i<height;i++)            //行数  height { for (j=0;j<width;j++)           //列数 width  { fseek(fp, 54+1352*i+3*j, SEEK_SET); fread(&A[i][j],1,1,fp); } }这个有没有错。。。。。。读取少量值没问题，全部读取就会出错。。是不是VC++6.0平台的问题？

user: user-2
content: 1. 永远用二进制模式打开文件 		fopen时mode参数加上"b"否则你可能花了一个通宵也弄不明白为什么一星期 	前正常运行的运行程序为什么最近老是出错。(Windows平台上才会出现哦！)  2. 避免以更新模式打开文件 		fopen时mode参数不要用"+"，只要可能，要么读方式打开，要么写方式打开。 如果 	必须以更新模式打开文件，  记得在读写之间进行文件刷新 （flush） 或文件定位操作 	（fseek , fsetpos , rewind）。

user: user-1
content: 常量也有类型： C++ Integer Constants Integer constants are constant data elements that have no fractional parts or exponents. They always begin with a digit. You can specify integer constants in decimal, octal, or hexadecimal form. They can specify signed or unsigned types and long or short types.  Syntax  integer-constant :  decimal-constant integer-suffixopt octal-constant integer-suffixopt hexadecimal-constant integer-suffixopt 'c-char-sequence'  decimal-constant :  nonzero-digit decimal-constant digit  octal-constant :  0 octal-constant octal-digit  hexadecimal-constant :  0x hexadecimal-digit 0X hexadecimal-digit hexadecimal-constant hexadecimal-digit  nonzero-digit : one of  1 2 3 4 5 6 7 8 9  octal-digit : one of  0 1 2 3 4 5 6 7  hexadecimal-digit : one of  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F  integer-suffix :  unsigned-suffix long-suffixopt long-suffix unsigned-suffixopt  unsigned-suffix : one of  u U  long-suffix : one of  l L  64-bit integer-suffix :  i64  To specify integer constants using octal or hexadecimal notation, use a prefix that denotes the base. To specify an integer constant of a given integral type, use a suffix that denotes the type.  To specify a decimal constant, begin the specification with a nonzero digit. For example:  int i = 157;   // Decimal constant int j = 0198;  // Not a decimal number; erroneous octal constant int k = 0365;  // Leading zero specifies octal constant, not decimal  To specify an octal constant, begin the specification with 0, followed by a sequence of digits in the range 0 through 7. The digits 8 and 9 are errors in specifying an octal constant. For example:  int i = 0377;   // Octal constant int j = 0397;   // Error: 9 is not an octal digit  To specify a hexadecimal constant, begin the specification with 0x or 0X (the case of the “x” does not matter), followed by a sequence of digits in the range 0 through 9 and a (or A) through f (or F). Hexadecimal digits a (or A) through f (or F) represent values in the range 10 through 15. For example:  int i = 0x3fff;   // Hexadecimal constant int j = 0X3FFF;   // Equal to i  To specify an unsigned type, use either the u or U suffix. To specify a long type, use either the l or L suffix. For example:  unsigned uVal = 328u;             // Unsigned value long lVal = 0x7FFFFFL;            // Long value specified                                    //  as hex constant unsigned long ulVal = 0776745ul;  // Unsigned long value

user: user-0
content: 谢谢。也不行.这是读取b分量的值 有没有问题 for(i=0;i<height;i++)            //行数  height { for (j=0;j<width;j++)           //列数 width  { fseek(fp, 54+1352*i+3*j, SEEK_SET); fread(&A[i][j],1,1,fp); } }

user: user-1
content: 54+1352*i+3*j 改为 54UL+1352UL*i+3UL*j

user: user-2
content: if((fp=fopen( "d:\\1.bmp", "r"))==NULL)  ===> if((fp=fopen( "d:\\1.bmp", "rb"))==NULL)

user: user-0
content: 谢谢。bmp宽度为450，又因为有rgb三个分量，每行有1350个细节，而且有要是4的倍数，最后成为1352.这点没问题。 当读取少量像素值，比如30个的时候没问题，但是超过某个值的时候就出错了

user: user-1
content: 提醒：bmp每行像素数据的字节数必须是4的倍数。  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。

user: user-0
content: 引掉也没问题，其实LineLength已经修正过了，就是下面的1352 fseek(fp, 54+1352*i+3*j, SEEK_SET); fread(&A[i][j],1,1,fp);  我是想说读取少量像素值没问题，但是要全部读完结果就有问题了

user: user-5
content: //r=LineLength%4; //if(r!=0) //r=4-r; //else r=0; //while( LineLength % 4 != 0 )             // 修正LineLength使其为4的倍数    // ++LineLength;  这块不能注释掉的哦，图像中每行字节数必须是4的倍数，否则取得数值就会有偏差，并且分配的内存有可能偏小导致内存溢出