Question: C语言如何读取文件夹下的同一类型文件

不是把全部文件中的数据先读入内存或先读入内存在写到一个文件中。 是用个list.txt文件，用system("dir /a-d /b x:\\adir\\*.bmp >list.txt");把x:\\adir\\目录下面的所有bmp文件名，保存到这个文件中，然后读出list.txt里面每行一个的文件名，然后逐个对bmp文件进行操作

仅供参考//将c:\\tmp文件夹下的所有文件的内容全部放到用malloc分配的内存中 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <io.h> struct FB {     char fn[256];     size_t fl;     char *b;     struct FB *next;     struct FB *prev; } *fh,*fb,*ft; char ln[256]; char fpn[256]; FILE *af; FILE *f; int L,n; int main() {     system("dir /b /a-d c:\\tmp\\*.* >c:\\allfn.txt");     af=fopen("c:\\allfn.txt","r");     if (NULL==af) {         printf("Can not open file c:\\allfn.txt!\n");         return 1;     }     fh=NULL;     fb=NULL;     n=0;     while (1) {         if (NULL==fgets(ln,256,af)) break;         L=strlen(ln);         if ('\n'==ln[L-1]) ln[L-1]=0;         printf("read %s\n",ln);         strcpy(fpn,"c:\\tmp\\");         strcat(fpn,ln);         ft=(struct FB *)malloc(sizeof(struct FB));         if (NULL==ft) {             printf("Can not malloc ft!\n");             fclose(af);             return 2;//之前的malloc在main退出后由操作系统自动free         }         printf("ft[%d]==%p\n",n,ft);         strcpy(ft->fn,fpn);         f=fopen(fpn,"rb");         if (NULL==f) {             printf("Can not open file %s!\n",fpn);             fclose(af);             return 3;//之前的malloc在main退出后由操作系统自动free         }         ft->fl=_filelength(fileno(f));         ft->b=malloc(ft->fl);         if (NULL==ft->b) {             printf("Can not malloc ft->b!\n");             fclose(f);             fclose(af);             return 4;//之前的malloc在main退出后由操作系统自动free         }         printf("ft[%d]->b==%p\n",n,ft->b);         if (ft->fl!=fread(ft->b,1,ft->fl,f)) {             printf("fread error!\n");             fclose(f);             fclose(af);             return 5;//之前的malloc在main退出后由操作系统自动free         }         fclose(f);         ft->next=NULL;          if (NULL==fh) {             ft->prev=NULL;             fh=ft;         } else {             fb->next=ft;             ft->prev=fb;         }         fb=ft;         n++;     }     fclose(af);     printf("-----list-----\n");     for (ft=fh;NULL!=ft;ft=ft->next) {         printf("%8d %s\n",ft->fl,ft->fn);         if (NULL!=ft) fb=ft;     }     printf("-----free-----\n");     n--;     if (NULL!=fh) {         for (ft=fb->prev;NULL!=ft;ft=ft->prev) {             if (NULL!=ft->next->b) {                 printf("ft[%d]->b==%p\n",n,ft->next->b);                 free(ft->next->b);             }             if (NULL!=ft->next) {                 printf("ft[%d]==%p\n",n,ft->next);                 free(ft->next);             }             n--;         }         if (NULL!=fh->b) {             printf("ft[0]->b==%p\n",fh->b);             free(fh->b);         }         printf("ft[0]==%p\n",fh);         free(fh);     }     return 0; } //C:\tmp\tmp\Debug>dir /a-d c:\tmp // 驱动器 C 中的卷是 C_HD5_1 // 卷的序列号是 1817-D526 // // c:\tmp 的目录 // //找不到文件 // //C:\tmp\tmp\Debug>tmp //找不到文件 //-----list----- //-----free----- // //C:\tmp\tmp\Debug>dir /a-d c:\tmp // 驱动器 C 中的卷是 C_HD5_1 // 卷的序列号是 1817-D526 // // c:\tmp 的目录 // //2011-06-30  18:04            44,840 my_c.rar //2011-06-30  17:18             1,036 err.frm //2011-06-30  14:32            14,243 出租.txt //2011-06-28  12:08            23,681 MSDN98书签.txt //             4 个文件         83,800 字节 //             0 个目录 17,041,870,848 可用字节 // //C:\tmp\tmp\Debug>tmp //read my_c.rar //ft[0]==00421800 //ft[0]->b==00520068 //read err.frm //ft[1]==00421670 //ft[1]->b==0052AFC0 //read 出租.txt //ft[2]==00421530 //ft[2]->b==00378F28 //read MSDN98书签.txt //ft[3]==004213F0 //ft[3]->b==0052B3F8 //-----list----- // 44840 c:\tmp\my_c.rar //  1036 c:\tmp\err.frm // 14243 c:\tmp\出租.txt // 23681 c:\tmp\MSDN98书签.txt //-----free----- //ft[3]->b==0052B3F8 //ft[3]==004213F0 //ft[2]->b==00378F28 //ft[2]==00421530 //ft[1]->b==0052AFC0 //ft[1]==00421670 //ft[0]->b==00520068 //ft[0]==00421800 // //C:\tmp\tmp\Debug>

引用 1 楼 zhao4zhong1 的回复:system("dir /b /a-d c:\\*.bmp >d:\\allbmpfiles.txt"); //读文件d:\\allbmpfiles.txt的内容即C:\\下所有bmp文件的名字 system("dir /b /a-d c:\\*.* >d:\\allfiles.txt"); //读文件d:\\allfiles.txt的内容即C:\\下所有文件的名字 system("dir /b /a-d /s c:\\*.* >d:\\allfilesinsub.txt"); //读文件d:\\allfilesinsub.txt的内容即C:\\下所有文件的名字包含子目录 system("dir /b /ad  c:\\*.* >d:\\alldirs.txt"); //读文件d:\\alldirs.txt的内容即C:\\下所有子目录的名字 请记住，能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作，而不要用各种API获取或者操作，因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时，API会处理的不全面或陷入死循环，而shell命令不会。因为要处理BMP文件里面的一些数据，我需要是逐个对文件进行处理，赵老师说的是把全部数据先读入到一个文件是吗？我现在的做法是用个list.txt文件，然后把目录下面的所有bmp文件名，列入这个文件中，然后在分别读出list.txt里面的文件名，然后对文件进行操作

大牛不說,我還快就說出API

简单点的方法是：获取文件名称之后判断是否以.bmp为后缀


Question: 关于指针的一个简单的问题

我自己总结了一下，是不是可以这么认为，++*p++ 凡是间接操作符可以直接接触到指针p的，都要直接操作指针P，凡是间接操作符，不能直接接触到指针P的。多要操作在指针自增或自减后的指针

哦，好像知道了，我理解的是错误的，*p++   后缀的++的优先级高于间接操作符。但是还是有一个地方不明白， p++先拷贝一份 p 的值，然后 在把P 的值 ++，最后在拷贝的那个值上求间接操作符。为什么不是在++后的值上求那个操作符呢？

乱总结 在 c 中，“! ~ ++ -- + - * (type) sizeof” 的优先级相同，此时应以 Associativity 来判断谁先执行，一般 一元 operator 的 Associativity 是 right to left，  所以 ，*p++ = *(p++), 至于 p 的值何时 update, 请看 置顶 的帖子  另外，在 c 中根本就没有所谓的 前置++, 后前置--的区别，  lz 可参阅 The C programming Language 书中 2.12 节


Question: 指针强制转换的问题

书里会讲数据类型强转  指针，就无所谓了

对于指针的强制转换，一般都是不安全的。

step by step

http://www.360doc.com/content/11/1114/21/7612246_164359679.shtml  需要用的多以后自己去理解

举个例子： int *p; p+1 会移动四个字节 如果强转成(char*) p+1则会移动一个字节

所谓类型，就是从某个地址开始，读取该类型大小的数据。 比如 char，就读 1 个字节。 int 4 个字节 (32位系统)

//C++ Operators //  Operators specify an evaluation to be performed on one of the following: //    One operand (unary operator) //    Two operands (binary operator) //    Three operands (ternary operator) //  The C++ language includes all C operators and adds several new operators. //  Table 1.1 lists the operators available in Microsoft C++. //  Operators follow a strict precedence which defines the evaluation order of //expressions containing these operators.  Operators associate with either the //expression on their left or the expression on their right;    this is called //“associativity.” Operators in the same group have equal precedence and are //evaluated left to right in an expression unless explicitly forced by a pair of //parentheses, ( ). //  Table 1.1 shows the precedence and associativity of C++ operators //  (from highest to lowest precedence). // //Table 1.1   C++ Operator Precedence and Associativity // The highest precedence level is at the top of the table. //+------------------+-----------------------------------------+---------------+ //| Operator         | Name or Meaning                         | Associativity | //+------------------+-----------------------------------------+---------------+ //| ::               | Scope resolution                        | None          | //| ::               | Global                                  | None          | //| [ ]              | Array subscript                         | Left to right | //| ( )              | Function call                           | Left to right | //| ( )              | Conversion                              | None          | //| .                | Member selection (object)               | Left to right | //| ->               | Member selection (pointer)              | Left to right | //| ++               | Postfix increment                       | None          | //| --               | Postfix decrement                       | None          | //| new              | Allocate object                         | None          | //| delete           | Deallocate object                       | None          | //| delete[ ]        | Deallocate object                       | None          | //| ++               | Prefix increment                        | None          | //| --               | Prefix decrement                        | None          | //| *                | Dereference                             | None          | //| &                | Address-of                              | None          | //| +                | Unary plus                              | None          | //| -                | Arithmetic negation (unary)             | None          | //| !                | Logical NOT                             | None          | //| ~                | Bitwise complement                      | None          | //| sizeof           | Size of object                          | None          | //| sizeof ( )       | Size of type                            | None          | //| typeid( )        | type name                               | None          | //| (type)           | Type cast (conversion)                  | Right to left | //| const_cast       | Type cast (conversion)                  | None          | //| dynamic_cast     | Type cast (conversion)                  | None          | //| reinterpret_cast | Type cast (conversion)                  | None          | //| static_cast      | Type cast (conversion)                  | None          | //| .*               | Apply pointer to class member (objects) | Left to right | //| ->*              | Dereference pointer to class member     | Left to right | //| *                | Multiplication                          | Left to right | //| /                | Division                                | Left to right | //| %                | Remainder (modulus)                     | Left to right | //| +                | Addition                                | Left to right | //| -                | Subtraction                             | Left to right | //| <<               | Left shift                              | Left to right | //| >>               | Right shift                             | Left to right | //| <                | Less than                               | Left to right | //| >                | Greater than                            | Left to right | //| <=               | Less than or equal to                   | Left to right | //| >=               | Greater than or equal to                | Left to right | //| ==               | Equality                                | Left to right | //| !=               | Inequality                              | Left to right | //| &                | Bitwise AND                             | Left to right | //| ^                | Bitwise exclusive OR                    | Left to right | //| |                | Bitwise OR                              | Left to right | //| &&               | Logical AND                             | Left to right | //| ||               | Logical OR                              | Left to right | //| e1?e2:e3         | Conditional                             | Right to left | //| =                | Assignment                              | Right to left | //| *=               | Multiplication assignment               | Right to left | //| /=               | Division assignment                     | Right to left | //| %=               | Modulus assignment                      | Right to left | //| +=               | Addition assignment                     | Right to left | //| -=               | Subtraction assignment                  | Right to left | //| <<=              | Left-shift assignment                   | Right to left | //| >>=              | Right-shift assignment                  | Right to left | //| &=               | Bitwise AND assignment                  | Right to left | //| |=               | Bitwise inclusive OR assignment         | Right to left | //| ^=               | Bitwise exclusive OR assignment         | Right to left | //| ,                | Comma                                   | Left to right | //+------------------+-----------------------------------------+---------------+

认清楚值的含义，再看下类型转换就可以了，思想，不要硬要看到什么才是什么


Question: 分配内存

那怎样判断是否分配了内存呢？

sizeof(str)求的是指针的大小

sizeof(char*)  就是计算一个字符指针的长度，和sizeof(int*)等等指针的值都是一样的。如果是sizeof(数组名)那么就是这个数组所占的字节空间(单个元素字节*元素个数)了

那需要char str[8]这样声明。  引用 楼主 wasdfgh951 的回复:#include "stdio.h" #include "string.h" #include <MALLOC.H> int main() {  	char * str; 	str=(char*)malloc(8*sizeof(char)); 	int b; 	b=sizeof(str)/sizeof(char); 	printf("%d",b); 	strcpy(str,"hello"); 	printf("%s\n",str); 	return 0; }  为什么b=4? 不是等于8吗？ 求解。。。

sizeof(str)  求的是指针的大小。

str 是一个指针，32位系统，楼主大哥  sizeof（str) 的值是 4

sizeof求的是类型大小，不是分配的内存块大小。 内存分配的大小由系统来管理，需要了解系统的API。你要计算分配的内存大小，应该用_msize（windows下）、malloc_usable_size（linux）。这两个函数都在malloc.h下。 char* str = (char*)malloc(8*sizeof(char)); size_t i = _msize(str)/sizeof(char);

str 是指針變量  所以STR本身是4字節,這個明白嗎?  char * str; 即宣告了一個裝指針的變量 str 本身是4字節 而str未知,指針未初始化時不確定內容,但肯定是1字節,因為你用了CHAR聲明  而b=sizeof(str)/sizeof(char); 沒意思.將一個數除1,CHAR的類型就是1,大部系統來說  與數組分別在於char c[200]當printf c 時 會輸出數組總大小 而char *c 時 只會輸出C 本身的大小   #include "stdio.h" #include "stdlib.h" #include "string.h"  int main() { char * str; if(!(str=(char*)malloc(8*sizeof(char)))) { printf("內存分配失敗 \n"); } strcpy(str,"hello");  printf("%d \n",sizeof(str)); printf("%d \n",sizeof(*str)); printf("%s \n",str);  free(str); //養成這種習慣  system("pause"); return 0; }

引用 楼主 wasdfgh951 的回复:#include "stdio.h" #include "string.h" #include <MALLOC.H> int main() {  	char * str; 	str=(char*)malloc(8*sizeof(char)); 	int b; 	b=sizeof(str)/sizeof(char); 	printf("%d",b); 	strcpy(str,"hello"); 	printf("%s\n",str); 	return 0; }  为什么b=4? 不是等于8吗？ 求解。。。  因为sizeof（str）指针str的大小。 为什么是4呢？--因为你的测试机是32位（4*8）的。 指针str是char *型的，它所指向的类型是char型的，它的值是malloc出的内存区首地址，它本身所占的内存区是一个32位的地址，所以，sizeof(str)就是32/8,也就是4了。

sizeof 常考的题 楼主太大意了 这算是基本问题了

引用 5 楼 wasdfgh951 的回复:那怎样判断是否分配了内存呢？  char * str = NULL; str=(char*)malloc(8*sizeof(char)); if( NULL == str ) {     printf("malloc failed!\n"); //很少会出现这中情况，除非内存不足了！ }

引用 5 楼 wasdfgh951 的回复:那怎样判断是否分配了内存呢？ 这个问题估计楼主没弄太清楚指针和sizeof的作用 首先sizeof的值是判断数据类型的到的    sizeof(str),这里的str本身是一个指针，str保存的是你分配的内存的地址而已，一个地址值实际上就是一个整型数值，也就是指针本身，不管str指向了一个多大的内存，他还是一个指针，就是固定的4个字节  如果想判断是否成功分配了内存，判断下malloc的返回值呗


Question: 单步调试问题

引用 6 楼 u012889234 的回复:不是NULL ，，因为前面有(struct Family *) 在linux下用gdb调试 可以打印出来。不懂你这个！！！  。。。难道空指针加上类型强转就不是空指针了？

这个具体看你的代码是怎么写的呢？

看你代码预期她应该是什么值了？

指针为NULL吧，应该不正常。

引用 楼主 pokerLee 的回复:请问在单步调试中下面的情况算是调试出正常值么~~  我用的编译器是codeblocks~~求指点~~ 这是个空指针啊。

引用 楼主 pokerLee 的回复:请问在单步调试中下面的情况算是调试出正常值么~~  我用的编译器是codeblocks~~求指点~~ 是否正常要看你struct Family *是否使用了 目测现实的是此时指针为NULL  要使用应先申请空间 <个人意见，出书扯淡>

为什么不用VS，谁推荐的？ 个人觉得新手最好用VC++和VS之类的，这类比较简单，适于上手，找人帮忙也容易，其他用的不多的，遇到问题了都没人来帮你


Question: 关于删除主串中的子串的问题，想了一个下午，没找到方法。

C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\memmove.c /*** *memmove.c - contains memmove routine * *       Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *       memmove() copies a source memory buffer to a destination buffer. *       Overlapping buffers are treated specially, to avoid propogation. * *******************************************************************************/  #include <cruntime.h> #include <string.h>  /*** *memmove - Copy source buffer to destination buffer * *Purpose: *       memmove() copies a source memory buffer to a destination memory buffer. *       This routine recognize overlapping buffers to avoid propogation. *       For cases where propogation is not a problem, memcpy() can be used. * *Entry: *       void *dst = pointer to destination buffer *       const void *src = pointer to source buffer *       size_t count = number of bytes to copy * *Exit: *       Returns a pointer to the destination buffer * *Exceptions: *******************************************************************************/  void * __cdecl memmove (         void * dst,         const void * src,         size_t count         ) {         void * ret = dst;  #if defined (_M_IA64) || defined (_M_AMD64)          {           __declspec(dllimport)           void RtlMoveMemory( void *, const void *, size_t count );          RtlMoveMemory( dst, src, count );          }  #else  /* defined (_M_IA64) || defined (_M_AMD64) */         if (dst <= src || (char *)dst >= ((char *)src + count)) {                 /*                  * Non-Overlapping Buffers                  * copy from lower addresses to higher addresses                  */                 while (count--) {                         *(char *)dst = *(char *)src;                         dst = (char *)dst + 1;                         src = (char *)src + 1;                 }         }         else {                 /*                  * Overlapping Buffers                  * copy from higher addresses to lower addresses                  */                 dst = (char *)dst + count - 1;                 src = (char *)src + count - 1;                  while (count--) {                         *(char *)dst = *(char *)src;                         dst = (char *)dst - 1;                         src = (char *)src - 1;                 }         } #endif  /* defined (_M_IA64) || defined (_M_AMD64) */          return(ret); }

C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\strstr.c /*** *strstr.c - search for one string inside another * *       Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *       defines strstr() - search for one string inside another * *******************************************************************************/  #include <cruntime.h> #include <string.h>  /*** *char *strstr(string1, string2) - search for string2 in string1 * *Purpose: *       finds the first occurrence of string2 in string1 * *Entry: *       char *string1 - string to search in *       char *string2 - string to search for * *Exit: *       returns a pointer to the first occurrence of string2 in *       string1, or NULL if string2 does not occur in string1 * *Uses: * *Exceptions: * *******************************************************************************/  char * __cdecl strstr (         const char * str1,         const char * str2         ) {         char *cp = (char *) str1;         char *s1, *s2;          if ( !*str2 )             return((char *)str1);          while (*cp)         {                 s1 = cp;                 s2 = (char *) str2;                  while ( *s1 && *s2 && !(*s1-*s2) )                         s1++, s2++;                  if (!*s2)                         return(cp);                  cp++;         }          return(NULL);  }

好像还是不行哦，还是高兴的太早了，那一段删除字符串怎么就搞不出来呢

其中，CNP 没起到作用，忘记删除了。

/* Note:Your choice is C IDE */ #include "stdio.h" #include "string.h" char* ptr (char * p1, char * p2); int  del_substr ( char * st1, char * st2); int main() {	char * d; 	int cmp,cnp,cp,clp;  	char  a [100]= "zsdhfsj";  	char  b[100] = "sdhfsj";  	cnp = strlen(a);  	cp = strlen(b);  	d = ptr(a,b);  	cmp = del_substr(a,b);  	if(cmp)  	{  			for(clp = 0;clp<cp;clp++)  			{  				a[d -a] = a[d - a + cp];  				d++;	   			}  			printf("%s",a);			  	}  	else  	printf("没有任何子串");  	 } char * ptr (char * p1, char * p2) { 	char *str1,*str2; 	for(str1 = p1;*str1 != '\0';str1++) 		for(str2 = p2; *str2 != '\0';str2++) 			if(*str1 == *str2) 			return str1; 			 	return NULL; 	 } int del_substr( char * st1, char *st2) { 	char * temp; 	int i,count,p; 	count = 0; 	i = strlen(st2); 	if (st1 == NULL && st2 == NULL)	 		return 0; 	temp = ptr(st1 ,st2); 	if(temp == NULL) 		return 0; 	for(p = 0;p<i;p++) 		if(*temp++ == *st2++) 			count ++; 			if(i == count) 			return 1; 			 	return 0; 			 			 } 今天想了一下午，外加一晚上，才做出这个题目。是不是我不适合学C语言？ 没有用标准库函数

不能用strlen函数。

引用 3 楼 N_sev7 的回复:首先要找到子串在主串中的位置，然后删除 估计这题目是想考一下你怎么从主串中找到子串 子串匹配算法，建议看下KMP算法 +1  基本用KMP算法就可以了

仅供参考#include <stdio.h> #include <string.h> #include <locale.h> char s[256]; char *p; int r,n,i; int main() {     setlocale(LC_ALL,"chs");     while (1) {         printf("请输入一行文字(空行结束),\"%%20\"将替换为\" \",\"你懂得\"将替换为\"XXXXXX\":\n");         fgets(s,256,stdin);         if ('\n'==s[0]) break;         p=s;         while (1) {             p=strstr(p,"%20");             if (p) {                 memmove(p+1,p+3,strlen(p)-3+1);                 p[0]=' ';             } else break;         }         p=s;         while (1) {             p=strstr(p,"你懂得");             if (p) {                 memmove(p+6,p+6,strlen(p)-6+1);                 for (i=0;i<6;i++) p[i]='X';             } else break;         }         printf("%s",s);     }     return 0; } //请输入一行文字(空行结束),"%20"将替换为" ","你懂得"将替换为"XXXXXX": //abcdefg%20helloworld%20something.pdf //abcdefg helloworld something.pdf //请输入一行文字(空行结束),"%20"将替换为" ","你懂得"将替换为"XXXXXX": //这是测试文字你懂得，在这个你懂的地方，就得做你懂得的事 //这是测试文字XXXXX，在这个你懂的地方，就得做XXXXX的事 //请输入一行文字(空行结束),"%20"将替换为" ","你懂得"将替换为"XXXXXX": //

错了 if ('\n' == *(str+i)) 改为 if ('\0' == *(str+i))

int del_substr(char *str ,char const * substr) {     int iSubstrLen = 0;     int i = 0;     int j = 0;     if ((NULL == str) || (NULL == substr))     {         return 0;     }      iSubstrLen = strlen(substr);     while(1)     {         if ('\n' == *(str+i))         {             return 0;         }          if (*substr == *(str+i))         {             for (j = 0;j<iSubstrLen;j++)             {                 if ('\0' == *(substr+j))                 {                     return 1;                 }                  if (*(substr+j) != *(str+i+j))                 {                     j = iSubstrLen;                 }             }         }          i++;     }  }  未验证


Question: 移位运算问题

int i= 16982； int k = i >> 9; int j = i & ((1<<9)-1);

直接低9位与1相与，其他位与0相与，就像@turingo写的 : int j = i * 0x1ff

int i = 16982; /* 这样j=001010110 */ int j = i & 0x1ff; /* 这样k=100001 */ int k = i >> 9;  引用 楼主 sanshao1314 的回复:各位好，对于移位运算弱弱的问个问题。    比如一个整形    int i= 16982；    它的二进制：100001001010110    int k = i >> 9;    这个时候得到的就是：100001 = 32；    我要问的就是我如何得到被移位掉的数呢，这里就是001010110被移位掉了，我想得到这个数不知道怎么操作，望各位指点一二。

新手也来学习啊

100001 = 33!! 这和小学学过的求余数道理是一样的，被除数=除数*商+余数。此处为： 16982=33*（2^9）+ X。 这个问题，还可以将16982左移（16-9）位后，再右移回来就得到了你要的数了，高位的 100001 在运算中被截掉了。

十分感谢各位的帮助，谢谢。


Question: 四柱汉诺塔问题

3Q!后来老师讲了，思想懂了，程序还是编不出来！

引用 2 楼 zhao4zhong1 的回复:“给定一个小点的输入，完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门！ 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出大神能不能不水？

汉诺塔问题,是理解递归的最佳案例  // Hanoi.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <windows.h> #include <fstream> using namespace std; ofstream file; #define OUTPUTRESULT cout //把n个盘子,从A,借助B,C,移动到Dest //把盘子从上到下,从1至N进行编号 void hanoi(int n,char A,char B,char C,char Dest ){ 	if(n==1) 	{OUTPUTRESULT<<"[ "<<n<<" ]"<<A<<"->"<<Dest<<endl;return;} 	//先把n-1个盘子,从A,借助B,Dest,移动到C 	hanoi(n-1,A,B,Dest,C); 	//再把第n个盘子,从A直接移动到Dest 	OUTPUTRESULT<<"[ "<<n<<" ]"<<A<<"->"<<Dest<<endl; 	//然后再把上面放在C上面的盘子,借助于A,B,移动到Dest. 	hanoi(n-1,C,A,B,Dest); } int _tmain(int argc, _TCHAR* argv[]) { 	file.open("c:/han.txt"); 	hanoi(4,'A','B','C','D'); 	system("pause"); 	return 0; }   用递归来表达,整个的函数的主义是十分的流畅


Question: 求C语言指针的学习方法，

指针是一种表示地址的数据。

就是地址，我觉得c++primer里面讲的很清楚的

建议学C语言反汇编，指针在汇编里看着很简单，C里有时由于语法看着复杂导致你看不懂，例如 (*(void (*)( ) )0)( ) 其实汇编就两行，傻子都懂  xor eax,eax call eax

代码和数据都有可能占用内存，因此都可能会有地址，指针是一种储存地址的数据。  变量是数据的一种，数据有常量，和变量两种。  常量，有些编译后，不需要单独的存储空间，于是就不给它安排内存（不拥有地址）。 有些需要单独的存储空间，就把它当作变量对待，给它安排内存（拥有地址）。  有些必须存储的常量，有些时候，编译器会安排到常量区，这些常量，就成为不可改写的常量（修改它会产生异常，这是运行时错误）。  而变量，只要不被优化掉，一般给它安排内存（拥有地址）。  指针就是记录代码（通常是函数），或者数据（通常是变量），的地址的数据，包括指针常量和指针变量。  比如 0xa0000000 是是图形格式，直接写屏地址。      0xb0000000 是字符格式，接写屏地址。  这两个都是指针常量。  至于各种指针的定义，先看数据或者函数类型，再看 * 的位置。

指针存的就是个地址，只不过在读的时候按照指针的类型从内存中读取相应类型大小的空间而已

每个变量都有自己在内存中存储的地址。 指针也不例外。说得很对。。。。。。。。。。

每个变量都有自己在内存中存储的地址。 指针也不例外，本身是一个整型，与普通变量不同的只是，普通变量存的是你要用到的实际数字，比如int a=123中的123；而指针存的也是一个数字，但这个数字的值可能对于你来说毫无意义，它代表另一个变量的地址。比如int * p=&a，p本身的值为a的地址（如0x4067E3FF），而*p的值是p指向的变量的值，=a=123。

函数指针就是代码段里函数的入口地址，对象的指针就是对象的首地址。

指針的藝術一書也很好

学会用工具来辅助自己理解，比如debugger。

从本质上去理解指针吧，指针变量本质上也是变量，和普通的变量的区别在于其存放的是地址值（也是一个数值，一般比较大），而不是普通变量存放的是数值。指针指向另一个变量，是将另一个变量的地址值赋值给了该指针。

虽说指针存的就是地址,但是有些书上写的不好懂,尤其中国人写的书,建议楼主看看外国人写的书上是怎么解释的

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495 //char (*(*x[3])())[5];//x是什么类型的变量? // //分析C语言声明，关键是搞清楚这个变量是个什么东西（函数、指针、数组）， //是函数那么剩下的就是他的参数和返回值， //是指针那剩下部分是说明他指向什么， //是数组剩下的部分就是说明数组的成员是什么类型。 //解析C语言声明规则： //从左侧第一个标识符开始，按照优先级进行结合。*表示是..的指针，const表示只读的，volatile表示可变的，[]表示是数组，()表示是函数。 // //x和[3]结合说明是一个大小为3的数组，该数组指向了一个指针，该指针指向一个函数，该函数的无参数，返回一个指针，该指针指向一个大小为5的char型数组 #include <stdio.h> #include <typeinfo.h> char num[5]; char (*x00())[5] {     return # } int main() {     char (*x000)[5];//返回值     char (*(x00)())[5];//函数原型，参数为空，返回值为指针     char (*(*x0)())[5];//数组的元素，是个函数指针     char (*(*x[3])())[5];//是个数组，大小为3      x0 = x00;     x[0] = x0;     x[1] = x0;     x[2] = x0;     printf("typeid(x).name() is %s\n",typeid(x).name());     return 0; } //typeid(x).name() is char (* (__cdecl**)(void))[5]

看书，了解概念；敲一敲书上的代码，编译一遍历；代码加上断点，逐步调试，看看每一步都发生了什么（指针的地址，指针所指向的地址，指针多指向的值等等）。N遍之后自然就清晰了。

引用 2 楼 jerry_dqh 的回复:[quote=引用 楼主 zhang0804140227 的回复:] 在学习指针的时候无线困惑，刚开始还懂点，但是随着学习的深入，什么函数指针，对象指针，不知不觉头脑全乱了，现在看见指针就头疼，看见指针的星号就有点胆怯了，越来越觉得指针不好学了。 但是又必须要学，求以前有这些困惑的人分享你们的学习心得，指导下我怎么才能进一步学习指针，更加高效的学习指针，求人品啊。。。 看一下 C和指针 这本书[/quote]  恩 这本书很好！

引用 楼主 zhang0804140227 的回复:在学习指针的时候无线困惑，刚开始还懂点，但是随着学习的深入，什么函数指针，对象指针，不知不觉头脑全乱了，现在看见指针就头疼，看见指针的星号就有点胆怯了，越来越觉得指针不好学了。 但是又必须要学，求以前有这些困惑的人分享你们的学习心得，指导下我怎么才能进一步学习指针，更加高效的学习指针，求人品啊。。。 看一下 C和指针 这本书

不管什么类型的指针，都存的是一个地址而已，多练练吧，就熟悉了


Question: C语言菜鸟问题

用那个库函数创建 文件？google!

加一次判断 文件不存在，就open失败，进入判断然后提示用户是否创建，是的话，重新open一次，加上 O_CREAT

输入确认，if判断？

楼主你是使用 CreateFile 自己创建吗？还是你是在 MFC 中写的程序？  如果是 CreateFile的话，你自己加判断语句就可以判断的呀。


Question: 数组与随机数问题

自行输入百位大数？你想每次调试都敲几百次键盘吗？

一个种子可以得到一个序列 一个序列可以源源不断产生随机数

LZ随机函数会调用不？ 给你一个数组依次置数组的每个元素会不？

楼上说的很清楚了。补充下为什么要用数组： 因为你用unsigned int型做数据的话，那么他只能表示（-2^31 -- 2^31-1）这么大的数据long long 也是有局限的，达不到你想要的（大数）精度，多以借助“数组”来模拟大数，例如int a[] = {1,2,3} 可以表示123.这样就不会有精度的限制了。

这就是产生随机数的原理 你看看还有什么不明白的地方

#include <stdio.h> #include <time.h>  int main() { 	int a[100], i; 	// 设置随机函数的种子  	srand(time(NULL)); 	for(i = 0; i < 100; i++) 	{ 		// 最高位不能为零  		// rand()%max ： 表示产生的随机数在0~max 之间  		if(i == 0){  			a[i] = rand()%10; 			while(a[i]==0) 				a[i] = rand()%10; 		}else { 	  			a[i] = rand()%10; 		}  	} 	for(i = 0; i < 100; i++) 		printf("%d", a[i]); 	return 0; }

google 大数运算


Question: 关于malloc的出现非内存空间不足的问题

引用 2 楼 user-1 的回复:filelist[filecount][len + 1] = '\0'; 越界了，应该是 filelist[filecount][len] = '\0'; 额，谢了！

#include "header.h" #include <sys/stat.h> #include <sys/types.h> #include <dirent.h> #include <string.h>  char* filelist[]; int filecount = 0;  int listfile(char *pathname){  	if (pathname == NULL) 		return -1; 	struct stat statbuf; 	struct dirent *dirp; 	DIR *dp; 	char dir[256];  	if ((dp = opendir(pathname)) == NULL){ 		fprintf(stderr, "can not open directory: %s\n",pathname); 		return -1; 	} 	while ((dirp = readdir(dp)) != NULL){ 		snprintf(dir,256, "%s/%s", pathname, dirp->d_name); 		lstat(dir, &statbuf); 		if (S_ISDIR(statbuf.st_mode)){ 			if (strcmp(".", dirp->d_name) == 0 || strcmp("..", dirp->d_name) == 0) 				continue; 			listfile(dir); 		} 		else { 			if (S_ISREG(statbuf.st_mode)){ 				char *p; 				int len; 				if ((p = strrchr(dirp->d_name, '.')) != NULL) 					if (strcmp(p, ".h") == 0 || strcmp(p, ".c") == 0) { 						len = strlen(dir); 						if ((filelist[filecount] = (char *)malloc(len + 1)) == NULL){ 							printf("dynamic memory overflow\n"); 							return -1; 						} 						p = filelist[filecount]; 						strncpy(p, dir, len); 						filelist[filecount][len + 1] = '\0'; 						filecount++; 						printf("%d\n",filecount); 					} 			} 		} 	} 	closedir(dp); 	return 0; }  int main(void){ 	listfile("/home/shuxiang/nginx/src"); 	int i; 	printf("%d\n",filecount); 	for (i = 0; i < filecount; i++){ 		printf("%s\n",filelist[i]); 		free(filelist[i]); 	} 	return 0; }


Question: LINUX抓狂问题

感谢各位  按大家说的已经解决

fflush(stdout)

引用 4 楼 SKATE11 的回复:引用 1 楼 adlay 的回复:标准输出有缓冲的, 后面加一句 fflush(stdout); 来冲刷一下吧不行啊  要是我去掉select的那段操作fprintf(stdout, "server:")才能在正常时间输出。 不然会在整段程序执行完才显示出来 #include <sys/select.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <unistd.h>  int main(){ 	char sendbuf[1024]; 	struct timeval tv; 	fd_set readfds; 	tv.tv_sec=10; 	tv.tv_usec=500000; 	FD_ZERO(&readfds); 	FD_SET(0, &readfds);  	fprintf(stdout, "server:"); //	fflush(stdout);  	select(0+1, &readfds, NULL, NULL, &tv); 	if(FD_ISSET(0, &readfds)){ 		gets(sendbuf); 	} 	else 	{ 		printf("Time out .\n"); 	}  	return 0; }   gcc试了下 加上fflush(stdout);  应该是没问题的 # ./a.out  server:Time out .  不加的话就会后输出，符合上面说的 # ./a.out  test server:[root@dc-work workspace]#   不知到楼主是什么编译器

上面两位说的对，是有缓冲滴，默认是行缓冲，碰到‘\n’或者缓冲区满了才输出 要么如第一位说的用fflush(stdout)， 强制输出缓冲区的 或者每次输出后面加'\n',也是可以的

fprintf(stdout, "server:")加个回车看看，标准IO是带缓冲的。

标准输出有缓冲的, 后面加一句 fflush(stdout); 来冲刷一下吧


Question: 镜头分割

估算画面变化超过一定程度就可以吧.


Question: Microsoft Visual C++ 2010 问题

#include "ex1-2-2.c" 跟 #include <ex1-2-2.c>  分別很大!  後者是在系統目錄中找檔案 前者是在目前目錄中找檔案,有需要能直接加上確實地扯

文件扩展名应该是CPP

#include "ex1-2-2.c"把对应文件的所有内容拷贝到了ex1-2.c里面了，ex1-2-2.c里的内容在工程里面有两份了，链接的时候当然会报错了，因为在ex1-2.c和ex1-2-2.c都找到了相同的名字。最好不要包含源文件，如果你要调ex1-2-2.c的函数，可以把函数原型和变量声明放在ex1-2-2.h里，然后包含.h文件就可以了。

引用 5 楼 yinan9 的回复:[quote=引用 2 楼 derekrose 的回复:] #include "ex1-2-2.c" 试试  谢谢！改成“”就没有这个问题了 但是出现了fatal error LNK1169: 找到一个或多个多重定义的符号 这个错误，但是却没有提示什么重复符号。 [/quote]  那是其他问题 重复定义的问题

引用 2 楼 derekrose 的回复:#include "ex1-2-2.c" 试试  谢谢！改成“”就没有这个问题了 但是出现了fatal error LNK1169: 找到一个或多个多重定义的符号 这个错误，但是却没有提示什么重复符号。

你要吓死人啊   引用源文件。。。

C文件也需要include吗，没必要吧。

#include "ex1-2-2.c" 试试

请大家帮忙看下


Question: c语言指针问题

int i = 100; 内存中有一个变量i，它的值是100 void* pvoid = &i; 内存中有一个指针pvoid，它指向变量i即它的值是i的地址，不关心它指向变量的类型 char* array = malloc(5*sizeof(void*)); 在内存中申请一段空间，大小为5*sizeof(void*)这么大，将地址保存到指针array，并声称指针array指向的数据为char类型  ((void **)array)[0] = pvoid; 首先，将array强制转换为void **类型的临时指针，也就是认为这个指针指向void*类型的数据，然后执行[0]操作，也就是获取这个指针指向的第0个数据，这个数据是void*类型，可以和pvoid相互赋值 ((void *)array)[0]; 首先，将array强制转换为void *类型的临时指针，也就是认为这个指针指向void类型的数据——void代表只记录地址不关心类型，因此这个指针不能执行*和[]操作，因为该操作获得的数据没有类型不能存在。因此该表达式非法。


Question: 关于for循环的问题，求指导

for( int i = 0; ; ); 这种在for循环中定义变量的行为，c语言直到c99标准才允许。但微软的VC把主要精力放在C++编译器上，C编译器一直停留在“只支持部分c99语法”的程度。 在其他跟随标准更新的C语言编译器中，以及任何C++编译器中，这种写法都是允许的。就不知道楼主记得的是哪个编译器了。

奥，明白了，谢谢。我可能是和C#里的搞混掉了

C语言中变量的声明和定义必须放在操作语句之前


Question: define函数-如何处理多参数?

C++的 var开头的一个啥可以支持不定的参数，楼上的那种如果是2参数转3参数咋个办，编译不过的

#define fun1 fun2 不就行了么

你还可以做成自己解析字符串的形式，参照sprintf,  "%d%f"后面可以自己跟一个自定义结束

这个要看你的3个参数是如何来的，如果是写死的，可以用宏定义，如果是动态的，要麻烦些，比如根据啥接口计算的，网络协议传的.==  #ifdef _a #define _XX_(A,B)  fun1(A) #else #define _XX_(A,B)   fun1(A,B) #endif

引用 1 楼 ggglivw 的回复:#ifdef _a #define fun1(x) fun2(X,x) #else #define fun1(x,y) fun2(X,x,y) #endif  调用处也加上条件编译  每个地方都加条件么? 这样就不符合预定义的初衷了?


Question: 大神们空降这里求指导！！！！

引用 1 楼 u011642451 的回复:mark.....??????


Question: 程序调用堆栈查找出现如下问题，求大侠指导，不胜感激啊

Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。

ASSERT宏使用是否正确？！ m_hObject如果不为空，就终止程序 否则就继续执行？？？


Question: 这段代码编译连接都成功，可是运行时没反应啊

引用 5 楼 caozhy 的回复:[quote=引用 4 楼 qq921965140 的回复:] [quote=引用 3 楼 caozhy 的回复:] [quote=引用 2 楼 qq921965140 的回复:] [quote=引用 1 楼 caozhy 的回复:] 运行没有反应分两种：一种程序运行完了没有输出，说明没有走到有输出的代码分支。还有就是程序没完没了，那就是有死循环。  调试下就知道了。能帮我看看那出错吗？看了快一个小时啦也没看出哪里错了[/quote] 调试会么，一行一行单步运行。[/quote]我还是菜鸟，不会啊！[/quote] 学会调试比学会写成程序更重要。[/quote]说的很对，明天我就去学调试。

引用 6 楼 max_min_ 的回复: void CreateList(LinkList & L, int n)  {          int i;     L=(LinkList)malloc(sizeof(LNode));     L->next=NULL;       for(i=n;i>0;--i)  {      LinkList p;     p=(LinkList)malloc(sizeof(LNode));     printf("input a char: ");//加一句这个吧！看是不是需要在等待用户输入了呢！     scanf("%c",&(p->data));        p->next=L->next;     L->next=p;       getchar(); //吃掉输入的回车符 } } 真的成功了！好鸡冻！太谢谢啦！送分！不过这里为什么要吃掉回车符啊？

引用 4 楼 qq921965140 的回复:[quote=引用 3 楼 caozhy 的回复:] [quote=引用 2 楼 qq921965140 的回复:] [quote=引用 1 楼 caozhy 的回复:] 运行没有反应分两种：一种程序运行完了没有输出，说明没有走到有输出的代码分支。还有就是程序没完没了，那就是有死循环。  调试下就知道了。能帮我看看那出错吗？看了快一个小时啦也没看出哪里错了[/quote] 调试会么，一行一行单步运行。[/quote]我还是菜鸟，不会啊！[/quote] 学会调试比学会写成程序更重要。

引用 3 楼 caozhy 的回复:[quote=引用 2 楼 qq921965140 的回复:] [quote=引用 1 楼 caozhy 的回复:] 运行没有反应分两种：一种程序运行完了没有输出，说明没有走到有输出的代码分支。还有就是程序没完没了，那就是有死循环。  调试下就知道了。能帮我看看那出错吗？看了快一个小时啦也没看出哪里错了[/quote] 调试会么，一行一行单步运行。[/quote]我还是菜鸟，不会啊！

引用 2 楼 qq921965140 的回复:[quote=引用 1 楼 caozhy 的回复:] 运行没有反应分两种：一种程序运行完了没有输出，说明没有走到有输出的代码分支。还有就是程序没完没了，那就是有死循环。  调试下就知道了。能帮我看看那出错吗？看了快一个小时啦也没看出哪里错了[/quote] 调试会么，一行一行单步运行。

引用 1 楼 caozhy 的回复:运行没有反应分两种：一种程序运行完了没有输出，说明没有走到有输出的代码分支。还有就是程序没完没了，那就是有死循环。  调试下就知道了。能帮我看看那出错吗？看了快一个小时啦也没看出哪里错了


Question: 负数补码最高位是否可以为0

1）用加法计算减法；那么只需要加法器的硬件实现，就可以同时计算加减法。 2）正数和负数，可以使用同一个方式，计算加减法；那么就不需要分别实现两套加法器了。

补码数表示的好处。 是可以统一整数的加减法。 包括 1）可以用加法计算减法。 2）正数和负数，可以使用同一个方式，计算加减法。

补码，有两种含义 一：补码编码 原码的编码方式是，不变。 反码的编码方式是，原码按位取反。 补码的编码方式，是反码加一。  二：   补码数，用来表示有符号整数。   0和正数的编码是原码。   负数的编码，是该数的绝对值的补码。   这样的表示方式，就是补码数表示。  C，C++有符号整数，就是整数的补码数表示。 C，C++无符号整数，就是整数的原码表示。  绝对值最大的负数，有点特殊，它的补码表示，就是他的绝对值（的无符号表示） 它取反+1 的结果，还是它本身。

最高位是1才是用来表示负数的呀 就拿8位二进制来说吧.总共可表示256个数. 正数的范围是:0至127 共128个数 负数的范围是:-128至-1 共128个数  你看正负数的范围是对称的,数学之美.

不可以

你说的D8H是负数，那它必定是8位了。然后你取反又拿他当16位的弄，显然问题很大。 不喜欢补码这种概念，其实就是数字循环翻转的问题，弄出一个补码反码，反而把本来可以很简单描述的问题搞复杂了。

8Bits: +0 =0 //-0 ,不存在,用来表示-128了

8Bits -128 是一个负数,除此之外的负数,都比较好处理.

说错了，你的问题是另一个问题，你举得例子是8位数的情况下的事。 那么我先以16位来举例，也就是D8H=0000 0000 1101 1000，那么取反后是1111 1111 0010 0111，然后+1 变成了1111 1111 0010 1000，这个没什么问题吧。 然后再说说8位的情况下，8位以unsigned来说，值是从0000 0000到1111 1111，也就是0-255，共256个数，但如果是有符号数那么整数就不可能那么多了，因为最高位是符号位，所以正整数是0000 0000 - 0111 1111也就是0 - 127，而负整数则是1000 0000 - 1111 1111 也就是-128 — -1，这样总共是256个数。而你举得D8，本身就是216超过了8位正整数最大值127了，所以已经是个负数了，你所说的是不成立的。

你想多了，取反的时候符号位是不变的，剩余位数取反+1

d8h  =00000000 11011000 -d8h =11111111 00100111+1 = 11111111 00101000  如果只是一字节的话,存不了小于-127的负数,d8h是216


Question: 程序无法完全运行，求指教

a = getchar();  改为：  clearerr( stdin ); while( ( a = getchar() ) == '\n' );

引用 1 楼 user-2 的回复:跟踪下，看看为何退出怎么追踪  每个指令结尾都是return 但运行完之后不会return只会退出

跟踪下，看看为何退出


Question: 程序错误~~求指教~~

引用 8 楼 pokerLee 的回复:问一下~~你调试的时候观察的变量是哪个？在哪设的断点？ 你要观察哪里，观察什么变量，就在哪里设断点咯。但你该不会是光标指向那一行的时候就记录值吧！要到下一行才算执行过。VS下看自动窗口，如果有修改过会变红色的。  查看完整的步骤时，最好写一下简单的测试用例，然后利用条件断点来看，可以省下不少时间。比如下面的例子，我设前两个人是第三人的父母，那么之前两个人就完全没必要判断了。   也可以直接定位到(*pmember1).p_to_pa=pmember2; 这个要观察的一行，查看执行前后的值变化

引用 9 楼 Adol1111 的回复:[quote=引用 8 楼 pokerLee 的回复:] 问一下~~你调试的时候观察的变量是哪个？在哪设的断点？ 你要观察哪里，观察什么变量，就在哪里设断点咯。但你该不会是光标指向那一行的时候就记录值吧！要到下一行才算执行过。VS下看自动窗口，如果有修改过会变红色的。  查看完整的步骤时，最好写一下简单的测试用例，然后利用条件断点来看，可以省下不少时间。比如下面的例子，我设前两个人是第三人的父母，那么之前两个人就完全没必要判断了。   也可以直接定位到(*pmember1).p_to_pa=pmember2; 这个要观察的一行，查看执行前后的值变化  [/quote]谢谢~~除了谢谢没别的感谢  引用 9 楼 Adol1111 的回复:[quote=引用 8 楼 pokerLee 的回复:] 问一下~~你调试的时候观察的变量是哪个？在哪设的断点？ 你要观察哪里，观察什么变量，就在哪里设断点咯。但你该不会是光标指向那一行的时候就记录值吧！要到下一行才算执行过。VS下看自动窗口，如果有修改过会变红色的。  查看完整的步骤时，最好写一下简单的测试用例，然后利用条件断点来看，可以省下不少时间。比如下面的例子，我设前两个人是第三人的父母，那么之前两个人就完全没必要判断了。   也可以直接定位到(*pmember1).p_to_pa=pmember2; 这个要观察的一行，查看执行前后的值变化  [/quote]方法了~~

引用 4 楼 Adol1111 的回复:[quote=引用 3 楼 pokerLee 的回复:] [quote=引用 1 楼 Adol1111 的回复:] while(current!=NULL)//改成这样，不是比较下一个不是NULL，不然最后一个无法比较 { 	int parents=0; 	last=first;//第一个开始查，而不是当前的下一个 	while(last!=NULL) 	{ 		if(related(current,last)) 			if(++parents==2) 				break; 		last=(*last).next; 	} 	current=(*current).next; }  bool related(struct Family *pmember1,struct Family *pmember2) {     //return set_ancestry(pmember1,pmember2)||set_ancestry(pmember1,pmember2);     //重复操作没有意义啊，改成下面这样，或者去掉该函数直接调用set_ancestry     return set_ancestry(pmember1,pmember2); }感觉还有些其他问题，代码模块上最好能拆解一下，一般一个某块在5-10行左右，最好不超过20行。main写的长了，完全可以再拆成3个函数。总之尽量的简单点，自己号管理，看代码也不累。每个函数间功能也尽可能单一，最好能光看命名不看代码就知道该某块的功能会更好额~~我感觉这个修改指示改变了指针~~并没有把关系函数修改过来啊~~我单步调试的时候运行到relate（）时（*current）.p_to_pa的内存没有改变~~求指点啊~~[/quote] 改了啊，你看看你的测试用例写的怎么样。你按贴出来的那个截图输入的，前两个结点是找不到父母的，第三个才有效果。我这边没问题，你看看是不是测试用例打错了。还是执行了没反应？[/quote]问一下~~你调试的时候观察的变量是哪个？在哪设的断点？

引用 4 楼 Adol1111 的回复:[quote=引用 3 楼 pokerLee 的回复:] [quote=引用 1 楼 Adol1111 的回复:] while(current!=NULL)//改成这样，不是比较下一个不是NULL，不然最后一个无法比较 { 	int parents=0; 	last=first;//第一个开始查，而不是当前的下一个 	while(last!=NULL) 	{ 		if(related(current,last)) 			if(++parents==2) 				break; 		last=(*last).next; 	} 	current=(*current).next; }  bool related(struct Family *pmember1,struct Family *pmember2) {     //return set_ancestry(pmember1,pmember2)||set_ancestry(pmember1,pmember2);     //重复操作没有意义啊，改成下面这样，或者去掉该函数直接调用set_ancestry     return set_ancestry(pmember1,pmember2); }感觉还有些其他问题，代码模块上最好能拆解一下，一般一个某块在5-10行左右，最好不超过20行。main写的长了，完全可以再拆成3个函数。总之尽量的简单点，自己号管理，看代码也不累。每个函数间功能也尽可能单一，最好能光看命名不看代码就知道该某块的功能会更好额~~我感觉这个修改指示改变了指针~~并没有把关系函数修改过来啊~~我单步调试的时候运行到relate（）时（*current）.p_to_pa的内存没有改变~~求指点啊~~[/quote] 改了啊，你看看你的测试用例写的怎么样。你按贴出来的那个截图输入的，前两个结点是找不到父母的，第三个才有效果。我这边没问题，你看看是不是测试用例打错了。还是执行了没反应？[/quote]我改错了~~谢谢大神~~这个程序折磨我半个月了~~你这个改法是对的~~我得好好看看自己思路错在哪了~~再次谢谢~~

引用 5 楼 zhao4zhong1 的回复:代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试是程序员必须掌握的技能之一。首先谢谢您的教诲~~我刚开始学习调试~~调试的结果是在relate()函数中(*current).p_to_pa和(*current).p_to_ma就没有变量值~~我也在找错误~~只是还没有经验~~上面大侠的指点并没有给我太多的指点~~我的想法是看看自己的想法和别人的正确答案差在哪~~所以希望大侠指点一下~~再次谢谢~~

引用 1 楼 Adol1111 的回复:while(current!=NULL)//改成这样，不是比较下一个不是NULL，不然最后一个无法比较 { 	int parents=0; 	last=first;//第一个开始查，而不是当前的下一个 	while(last!=NULL) 	{ 		if(related(current,last)) 			if(++parents==2) 				break; 		last=(*last).next; 	} 	current=(*current).next; }  bool related(struct Family *pmember1,struct Family *pmember2) {     //return set_ancestry(pmember1,pmember2)||set_ancestry(pmember1,pmember2);     //重复操作没有意义啊，改成下面这样，或者去掉该函数直接调用set_ancestry     return set_ancestry(pmember1,pmember2); }感觉还有些其他问题，代码模块上最好能拆解一下，一般一个某块在5-10行左右，最好不超过20行。main写的长了，完全可以再拆成3个函数。总之尽量的简单点，自己号管理，看代码也不累。每个函数间功能也尽可能单一，最好能光看命名不看代码就知道该某块的功能会更好 + +

引用 3 楼 pokerLee 的回复:[quote=引用 1 楼 Adol1111 的回复:] while(current!=NULL)//改成这样，不是比较下一个不是NULL，不然最后一个无法比较 { 	int parents=0; 	last=first;//第一个开始查，而不是当前的下一个 	while(last!=NULL) 	{ 		if(related(current,last)) 			if(++parents==2) 				break; 		last=(*last).next; 	} 	current=(*current).next; }  bool related(struct Family *pmember1,struct Family *pmember2) {     //return set_ancestry(pmember1,pmember2)||set_ancestry(pmember1,pmember2);     //重复操作没有意义啊，改成下面这样，或者去掉该函数直接调用set_ancestry     return set_ancestry(pmember1,pmember2); }感觉还有些其他问题，代码模块上最好能拆解一下，一般一个某块在5-10行左右，最好不超过20行。main写的长了，完全可以再拆成3个函数。总之尽量的简单点，自己号管理，看代码也不累。每个函数间功能也尽可能单一，最好能光看命名不看代码就知道该某块的功能会更好额~~我感觉这个修改指示改变了指针~~并没有把关系函数修改过来啊~~我单步调试的时候运行到relate（）时（*current）.p_to_pa的内存没有改变~~求指点啊~~[/quote] 改了啊，你看看你的测试用例写的怎么样。你按贴出来的那个截图输入的，前两个结点是找不到父母的，第三个才有效果。我这边没问题，你看看是不是测试用例打错了。还是执行了没反应？

引用 1 楼 Adol1111 的回复:while(current!=NULL)//改成这样，不是比较下一个不是NULL，不然最后一个无法比较 { 	int parents=0; 	last=first;//第一个开始查，而不是当前的下一个 	while(last!=NULL) 	{ 		if(related(current,last)) 			if(++parents==2) 				break; 		last=(*last).next; 	} 	current=(*current).next; }  bool related(struct Family *pmember1,struct Family *pmember2) {     //return set_ancestry(pmember1,pmember2)||set_ancestry(pmember1,pmember2);     //重复操作没有意义啊，改成下面这样，或者去掉该函数直接调用set_ancestry     return set_ancestry(pmember1,pmember2); }感觉还有些其他问题，代码模块上最好能拆解一下，一般一个某块在5-10行左右，最好不超过20行。main写的长了，完全可以再拆成3个函数。总之尽量的简单点，自己号管理，看代码也不累。每个函数间功能也尽可能单一，最好能光看命名不看代码就知道该某块的功能会更好额~~我感觉这个修改指示改变了指针~~并没有把关系函数修改过来啊~~我单步调试的时候运行到relate（）时（*current）.p_to_pa的内存没有改变~~求指点啊~~


Question: 圆环上数字移位

引用 2 楼 qq921965140 的回复:[quote=引用 1 楼 shangyu0801 的回复:] 仿照代码如下: (m - 65 +26-3)%26 + 65 带入测试：(65 - 65 + 23 )%26 +65 =88正确大神，你是怎么想出来的？膜拜膜拜！分全送你！[/quote] 额，呵呵，不敢当啊，跟数学题一样，多做些就熟悉了。

引用 1 楼 shangyu0801 的回复:仿照代码如下: (m - 65 +26-3)%26 + 65 带入测试：(65 - 65 + 23 )%26 +65 =88正确  [quote=引用 1 楼 shangyu0801 的回复:] 仿照代码如下: (m - 65 +26-3)%26 + 65 带入测试：(65 - 65 + 23 )%26 +65 =88正确[/1uote]能告诉我你是怎么想出来的吗？

引用 1 楼 shangyu0801 的回复:仿照代码如下: (m - 65 +26-3)%26 + 65 带入测试：(65 - 65 + 23 )%26 +65 =88正确大神，你是怎么想出来的？膜拜膜拜！分全送你！


Question: 逆位序建立单链表

引用 7 楼 shangyu0801 的回复:malloc分配的空间，在不用的时候必须要free掉。 代码参考： LinkList p = L->next ; while(p!= NULL){     L->next=p->next;     free(p);     p = L->next; }能顺带帮我看看这道题吗？发了半天没人回答。http://bbs.csdn.net/topics/390651239

引用 4 楼 qq921965140 的回复:[quote=引用 3 楼 user-2 的回复:] LinkList难不成是个指针？是的typedef struct  LNode {       char      data;  // 数据域       struct LNode   *next;  // 指针域    } LNode, *LinkList; [/quote]能顺带帮我看看这道题吗？发了半天没人回答。http://bbs.csdn.net/topics/390651239

引用 3 楼 user-2 的回复:LinkList难不成是个指针？http://http://bbs.csdn.net/topics/390651239 能顺带帮我看看这道题吗？发了半天没人回答。

引用 3 楼 user-2 的回复:LinkList难不成是个指针？是的typedef struct  LNode {       char      data;  // 数据域       struct LNode   *next;  // 指针域    } LNode, *LinkList;

LinkList难不成是个指针？

引用 1 楼 user-2 的回复:LinkList p;      p = (LinkList) malloc (sizeof (LNode));   这个写法不对吧？ 引用 1 楼 user-2 的回复:LinkList p;      p = (LinkList) malloc (sizeof (LNode));   这个写法不对吧？哪里不对啦，很对啊


Question: 堆损坏，求解释

引用 6 楼 u010749411 的回复:[quote=引用 5 楼 zhao4zhong1 的回复:] 崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。  [/code] 调试的时候一点问题都没有怎么办？[/quote] Win XP： drwtsn32 -i 运行你的程序 drwtsn32  Win7： http://www.nirsoft.net/utils/app_crash_view.html

引用 5 楼 zhao4zhong1 的回复:崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。  [/code] 调试的时候一点问题都没有怎么办？

崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。  判断是否越界访问，可以在数组的最后一个元素之后对应的地址处设置数据读写断点。如果该地址对应其它变量干扰判断，可将数组多声明一个元素，并设置数据读写断点在该多出元素对应的地址上。 #include <time.h> #include <stdlib.h> #include <windows.h> int main() {     int a,b[11];//本来是b[10]，为判断哪句越界，故意声明为b[11]      srand((unsigned int)time(NULL));//按两次F11，等黄色右箭头指向本行时，调试、新建断点、新建数据断点，地址：&b[10]，字节计数：4，确定。     while (1) {//按F5，会停在下面某句，此时a的值为10，b[10]已经被修改为对应0..4之一。         b[(a=rand()%11)]=0;         Sleep(100);         b[(a=rand()%11)]=1;         Sleep(100);         b[(a=rand()%11)]=2;         Sleep(100);         b[(a=rand()%11)]=3;         Sleep(100);         b[(a=rand()%11)]=4;         Sleep(100);     }     return 0; }

引用 3 楼 Adol1111 的回复:原因很多，比如你的指针访问了越界（可能使用时没什么问题），让系统误认为该空间属于malloc的空间，然后当你free这个指针的时候，实际上释放了一块未分配的空间，就导致堆破坏了。 如下代码：int main() { 	int ** p1=(int**)malloc(sizeof(int)*10); 	int *p2=(int *)malloc(sizeof(int)); 	p1[10]=p2;//访问越界 	free(p1);//误以为p1[10]也是malloc地址，一起释放，导致free了无效空间造成堆破坏 	return 0; }  for( i = 2; i < list[0].data; i++,x++) // list[0].data 的值 = 数据总数+1 //越界访问应该是没有的，要是越界访问，调试的时候应该会出错。。不过你说的第二点， //我感觉比较像出错原因。。。考虑到p1[10]=p2;//访问越界  不会发生。。 //就不太清楚了，我再看一下。。。多谢提示

刚才检查过了。。。queue的值没有变，依旧还是那个地址。。。。

释放前看看 queue 的值与 生成时是否一样


Question: 关于二维数组指针的问题

引用 5 楼 zhao4zhong1 的回复:计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495  我深受您的教导，现在正在学习汇编知识。从最低层理解程序语言。手上有一本《深入理解计算机系统》，讲的很好，难度是有的，但看懂每看懂一点就感到一点充实。

不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。

引用 4 楼 cheneydc 的回复:[quote=引用 2 楼 yiyidejian 的回复:] [quote=引用 1 楼 Idle_Cloud 的回复:] gcc测试了一下，正常。 难道VC测不出来吗？？不知道为什么float 二维数组就是不行！！[/quote]  gcc试了正常，结果不同应该和系统有关，可能是windows和linux处理内存部分的规则不太一样吧  int main(void)  {  float a[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};  int b[2][2] = {1,2,3,4};  float **p = (float**)a; int **pp = (int**)b;  printf("%f\n",*(a[0]+1)); # a[0]相当与一个整型指针， +1则增加一个单位，指向下一个整型，*(a[0]+1),取出指针指向的内容  printf("%d\n",(a[0]+1));  #此时输出的就是一个地址的值  printf("%d\n",(p+1));     #这个部分用gcc试的话和上面一样 printf("%f\n",*(p+1));    #如果想看出不同的话看下汇编吧，应该很明显就能看出不同的地方  printf("%d\n",*(b[0]+1)); printf("%d\n",(b[0]+1));  printf("%d\n",(pp+1)); printf("%d\n",*(pp+1));   return 0;  }  [/quote]thx~

引用 8 楼 niu91 的回复:[quote=引用 5 楼 zhao4zhong1 的回复:] 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495  我深受您的教导，现在正在学习汇编知识。从最低层理解程序语言。手上有一本《深入理解计算机系统》，讲的很好，难度是有的，但看懂每看懂一点就感到一点充实。[/quote]谢谢指点，想把这部分学的深入一点

引用 7 楼 u012348978 的回复:float **p = (float**)a; int **pp = (int**)b; 在使用（显示类型说明）的时候，你必须保证；你明白（那是什么），否则就不要使用（显示类型说明）。  正确用法如下； float (*p)[4] = a; int (*pp)[2] = b;  指针是一种强类型。在你搞清楚类型与类型的区别前，不要认为是指针只是一个类型。你说的对 一直都是很 牵强的在理解

引用 8 楼 niu91 的回复:[quote=引用 5 楼 zhao4zhong1 的回复:] 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495  我深受您的教导，现在正在学习汇编知识。从最低层理解程序语言。手上有一本《深入理解计算机系统》，讲的很好，难度是有的，但看懂每看懂一点就感到一点充实。[/quote] 有没有越来越接地气的感觉？

引用 2 楼 yiyidejian 的回复:[quote=引用 1 楼 Idle_Cloud 的回复:] gcc测试了一下，正常。 难道VC测不出来吗？？不知道为什么float 二维数组就是不行！！[/quote]  gcc试了正常，结果不同应该和系统有关，可能是windows和linux处理内存部分的规则不太一样吧  int main(void)  {  float a[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};  int b[2][2] = {1,2,3,4};  float **p = (float**)a; int **pp = (int**)b;  printf("%f\n",*(a[0]+1)); # a[0]相当与一个整型指针， +1则增加一个单位，指向下一个整型，*(a[0]+1),取出指针指向的内容  printf("%d\n",(a[0]+1));  #此时输出的就是一个地址的值  printf("%d\n",(p+1));     #这个部分用gcc试的话和上面一样 printf("%f\n",*(p+1));    #如果想看出不同的话看下汇编吧，应该很明显就能看出不同的地方  printf("%d\n",*(b[0]+1)); printf("%d\n",(b[0]+1));  printf("%d\n",(pp+1)); printf("%d\n",*(pp+1));   return 0;  }

指针好难啊。。。。。。。。。。

引用 1 楼 Idle_Cloud 的回复:gcc测试了一下，正常。 难道VC测不出来吗？？不知道为什么float 二维数组就是不行！！

gcc测试了一下，正常。


Question: 一段程序运行3秒后停止，进人下一段程序

引用 7 楼 u012690843 的回复:举个例子：贪吃蛇中到了一定分数进入奖励函数，30秒后跳出此函数，怎么办呢？ 先将贪吃蛇那个线程挂起， 将奖励函数放在另一个线程中执行后sleep 30秒后，再启动先前挂起的线程。

我上面的那段代码是linux的,windows也有signal函数,就是调用方法稍微有些不同而已 主线程先注册个信号事件, 然后新建一个子线程,子线程wait30秒,之后调用 raise函数,触发主线程信号处理函数,子线程自己退出  如果觉得麻烦,也可以试试用setTimer,不过需要有窗体 http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

举个例子：贪吃蛇中到了一定分数进入奖励函数，30秒后跳出此函数，怎么办呢？

启一个监控（守护）进程（线程），全局控制其他的不就行了？

《Windows核心编程》

如果是Windows，可以使用Sleep函数： Sleep(3000); // 3000毫秒，就是3秒。

程序要运行多久是代码决定的！ ps：题意有点不明确！那个3秒是要等等待3秒还是运行起来的程序只能3秒就运气另外一个程序呢？

用信号,不需要忙等的很不错   #include<stdio.h> #include<signal.h> void sigalrm_fn(int sig) { 	puts("alarm fired"); 	getchar(); } int main() { 	signal(SIGALRM, sigalrm_fn); 	alarm(5); 	while(1)puts("tick"); } Cygwin下的代码,windows上没有测试过

用系统内置函数调用 system("外部程序绝对路径");  例： system("/usr/bin/sh  urm.sh"); urm.sh 为参数  其实就是把一条在命令行输入的字符串放进""里面去，


Question: 指针啊啊！！指针间接访问跟用变量的区别？？

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

这个效率……应该可以忽略 硬要说的话，我猜下面那个高吧，毕竟通过指针要多访问一次内存

lz今天自己灵光一现解决了，原来是右结合少加了括号，那lz再问问上面两种写法哪个效率高？？

弱菜在痛哭


Question: 排序算法

引用 7 楼 Adol1111 的回复:[quote=引用 5 楼 lyw812152691 的回复:] 非常感谢你指定的错误地方，这些地方不注意就错了   a[j]=key;//这句写错了，不是swap，是赋值　 这个位置换掉swap　应该是不对的 看错了，我其实思路是用#4写的，主要是你这里用了swap有点不一样，我也没细改，把几个关键的地方改了下。 4#的是先把首项取出，然后直接覆盖，最后写回去。[/quote] 不管怎么说还是谢谢你

引用 5 楼 lyw812152691 的回复:非常感谢你指定的错误地方，这些地方不注意就错了   a[j]=key;//这句写错了，不是swap，是赋值　 这个位置换掉swap　应该是不对的 看错了，我其实思路是用#4写的，主要是你这里用了swap有点不一样，我也没细改，把几个关键的地方改了下。 4#的是先把首项取出，然后直接覆盖，最后写回去。

引用 4 楼 q745401990 的回复:void QuickSort(Type a[], int left, int right)   {       if(left < right)       {           int i = left, j = right, key = a[left];           do{               while(i < j && a[j] >= key)                   j--;               if(i < j) a[i++] = a[j];               while(i < j && a[i] < key)                   i++;               if(i < j) a[j--] = a[i];           }while(i != j);           a[i] = key;           QuickSort(a, left, i-1);           QuickSort(a, i+1, right);       }      }    left 是数组下标第一个存在的值，right是数组下标最后一个存在的值  稍微改了下 直接一个函数解决了   确实这个方法非常棒，代码量也少

引用 2 楼 lyw812152691 的回复:[quote=引用 1 楼 Adol1111 的回复:] 因为你的快排写得有问题，栈溢出了，然后吧size的值给覆盖了，那个15应该是你数据里的15，排序后正好在那个位置上。 能不能看是哪出的问题？？[/quote]void quick_sort(int a[],int left,int right) { 	int i=left,j=right;//不需要+1 	int key=a[left];  	if(left >=right) return ;  	while(1) 	{ 		while(a[j] > key && i<j) j--;//这里最好补上i<j 		while(a[i] < key && i<j) i++; 		if(i >= j) break; 		swap(&a[i],&a[j]); 		if(a[i] == key) 			j--; 		else 			i++; 	} 	a[j]=key;//这句写错了，不是swap，是赋值 	if(left <i-1) 		quick_sort(a,left,i-1); 	if(j+1<right) 		quick_sort(a,j+1,right); }  int main() { 	int a[]={0,-1,11,-14,5,15,-4,14}; 	int size=sizeof(a)/sizeof(a[0]); 	printf("size:%d\n",size); 	quick_sort(a,0,size-1);//参数传递错误，下标是0 - size-1 	printf("size:%d\n",size); 	for (int i=0;i<size;i++) 		printf("%d\t",a[i]); 	printf("\n"); 	return 0; }

引用 1 楼 Adol1111 的回复:因为你的快排写得有问题，栈溢出了，然后吧size的值给覆盖了，那个15应该是你数据里的15，排序后正好在那个位置上。  能不能看是哪出的问题？？


Question: 如何用C修改位图信息，扩展的话提下方向的思路

Image Magick


Question: C语言内联汇编问题，非常简单的问题，但就是不知道错哪

你看人家下面的代码多好，你的呢？

#include "stdafx.h" #include <stdio.h> int main() { 	long  a; 	_asm{ 			push eax 			push ecx 			mov eax,0x40001000 			mov ecx,dword ptr [eax+222h] 			mov a, ecx 			pop ecx 			pop eax  	} 	return 1; }


Question: 我这么实现栈有什么问题  为啥报错?

懂了就该结果了..

(*s)都没有申请空间就想给(*s)->base申请空间？

要初始化栈对象, 申请空间先...  status InitStack3(cstack **s)//初始化栈   {     *s = （cstack *)malloc(sizeof(cstack));     ...

谢谢 指点!!!

看来还是学艺不精啊 没有彻底的理解


Question: 求一古老指针问题

引用 9 楼 Ceronjyc 的回复:[quote=引用 4 楼 Adol1111 的回复:] _msize(p[i])分配的是内存块的大小，所以计算长度的话，还要除以sizeof()求得的保存类型的长度。 还有这里：p[i] = (char *)malloc(i+1);最好改成p[i] = (char *)malloc((i+1)*sizeof(char)); 当然对char来说是无所谓的，因为长度是1。  你之前的char **p  = (char**)malloc(1000);最好也改成我的那种。自己估算的长度是很麻烦的，不如让计算机来计算，你只要指定分配的个数，而不是内存块的大小。 你好，我想再寻一问题 void test2() { 	//申请一片内存空间 	char *str = (char*)malloc(13*sizeof(char));  	strcpy(str, "hello world"); 	printf("%s\n", str); 	free(str);  	if(str != NULL) 	{ 		strcpy(str, "hello world");		 		printf("%s\n", str); 	} } 为什么free(str)之后，还能正常输出“hello world” ？free让str不再指向之前申请的内存空间，str变成随机了指向，但为什么strcpy的时候不会报错？[/quote] 这个就是所谓的野指针，空间已经被回收了，但这个指针可不是随机指向，指针的地址还是原来的，不信的话你可以打印试试看。void test2() {     //申请一片内存空间     char *str = (char*)malloc(13*sizeof(char));     printf("%p\n",str);     strcpy(str, "hello world");     printf("%s\n", str);     free(str);     printf("%p\n",str);      if(str != NULL)     {         strcpy(str, "hello world");                 printf("%s\n", str);     } }至于free之后的指针，是否能访问这个就很难说了。有时候可以，有时候不可以。无论系统是否允许，都应该不去访问这种无意义的地址，因为人为的访问一个无效的地址是很危险的。 正确的作法是，在free之后，把这个指针重新指向NULL。也就是：free(str); str=NULL;

引用 4 楼 Adol1111 的回复:_msize(p[i])分配的是内存块的大小，所以计算长度的话，还要除以sizeof()求得的保存类型的长度。 还有这里：p[i] = (char *)malloc(i+1);最好改成p[i] = (char *)malloc((i+1)*sizeof(char)); 当然对char来说是无所谓的，因为长度是1。  你之前的char **p  = (char**)malloc(1000);最好也改成我的那种。自己估算的长度是很麻烦的，不如让计算机来计算，你只要指定分配的个数，而不是内存块的大小。 你好，我想再寻一问题 void test2() { 	//申请一片内存空间 	char *str = (char*)malloc(13*sizeof(char));  	strcpy(str, "hello world"); 	printf("%s\n", str); 	free(str);  	if(str != NULL) 	{ 		strcpy(str, "hello world");		 		printf("%s\n", str); 	} } 为什么free(str)之后，还能正常输出“hello world” ？free让str不再指向之前申请的内存空间，str变成随机了指向，但为什么strcpy的时候不会报错？

引用 5 楼 Ceronjyc 的回复:[quote=引用 4 楼 Adol1111 的回复:] _msize(p[i])分配的是内存块的大小，所以计算长度的话，还要除以sizeof()求得的保存类型的长度。 还有这里：p[i] = (char *)malloc(i+1);最好改成p[i] = (char *)malloc((i+1)*sizeof(char)); 当然对char来说是无所谓的，因为长度是1。  你之前的char **p  = (char**)malloc(1000);最好也改成我的那种。自己估算的长度是很麻烦的，不如让计算机来计算，你只要指定分配的个数，而不是内存块的大小。 万分感谢，要的就是这个_msize()。[/quote] 忘记说了，_msize()不是标准的，linux没有这东西，不过应该有其他的代替函数。

再次感谢两位大哥，很有收获。

引用 1 楼 user-2 的回复:哪里不一样呢？  p[i] = (char *)malloc(i+1); //这里没有清空或者赋值，直接strlen是得不到正确的长度的！ printf("p[%d]:%d\n", i, strlen(p[i]));  懂了，谢谢啊！

引用 4 楼 Adol1111 的回复:_msize(p[i])分配的是内存块的大小，所以计算长度的话，还要除以sizeof()求得的保存类型的长度。 还有这里：p[i] = (char *)malloc(i+1);最好改成p[i] = (char *)malloc((i+1)*sizeof(char)); 当然对char来说是无所谓的，因为长度是1。  你之前的char **p  = (char**)malloc(1000);最好也改成我的那种。自己估算的长度是很麻烦的，不如让计算机来计算，你只要指定分配的个数，而不是内存块的大小。 万分感谢，要的就是这个_msize()。

#include <stdio.h> #include <malloc.h>  void test4() { 	int i; 	char **p  = (char**)malloc(sizeof(char*)*50); 	int sum = 0; 	for(i=0; i<50; i++) 	{ 		p[i] = (char *)malloc(i+1); 		printf("p[%d]:%d\n", i, _msize(p[i])/sizeof(char)); 		sum +=_msize(p[i])/sizeof(char); 	} 	printf("sum: %d\n", sum); 	for(i=0; i<50; i++) 		free(p[i]); 	free(p);//别忘记释放p，它和p[i]两码事 }  int main(void) { 	test4(); 	getchar(); 	return 0; }

strlen是计算到第一个'\0'的位置的，你没有指定'\0'在哪里，所以取得的长度是不对的，甚至会超过数组分配的长度所以就错了。 计算内存分配的大小应该用其他方法，改成这种就OK了：printf("p[%d]:%d\n", i, _msize(p[i])/sizeof(char));

引用 8 楼 Adol1111 的回复:[quote=引用 5 楼 Ceronjyc 的回复:] [quote=引用 4 楼 Adol1111 的回复:] _msize(p[i])分配的是内存块的大小，所以计算长度的话，还要除以sizeof()求得的保存类型的长度。 还有这里：p[i] = (char *)malloc(i+1);最好改成p[i] = (char *)malloc((i+1)*sizeof(char)); 当然对char来说是无所谓的，因为长度是1。  你之前的char **p  = (char**)malloc(1000);最好也改成我的那种。自己估算的长度是很麻烦的，不如让计算机来计算，你只要指定分配的个数，而不是内存块的大小。 万分感谢，要的就是这个_msize()。[/quote] 忘记说了，_msize()不是标准的，linux没有这东西，不过应该有其他的代替函数。[/quote]  恩恩，查这个函数的时候网上有说，linux下是用这个malloc_usable_size()，在这个库/usr/include/malloc.h里。

引用 11 楼 Adol1111 的回复:你可以去google一下关于野指针的问题。 指向“垃圾”内存（不可用内存）的指针。哈，明白，再次感谢！

你可以去google一下关于野指针的问题。


Question: 【分享】C语言有关书籍

我想说，被骗了，广告

不用看这么多吧？一两本书，吃透了就好，然后开始试着编程就好。多了反而是负担

我和我的小伙伴都惊呆了~~~~~~

这么多书看到何时？

我还真是想看看这门语言  虽然也是刚开始学


Question: 实在不懂这个折半查找怎么老不AC？

scanf("%d",&n);去掉， search(a,n,m);中n改为N，没有必要输入n，你已经定义了N

大家帮忙看看吧


Question: 递归函数返回值的问题

引用 19 楼 baichi4141 的回复:首先，很多返回值使用EAX寄存器来返回，所以在这个例子里，因为你没有指定返回什么数值，调用该函数的地方就自动把函数退出后EAX寄存器中残留的数值当做返回值了。也就是说，你函数中最后使用EAX寄存器来保存的是什么值，它就认为你返回了什么值。至于29是怎么来的——printf函数返回的是打印出的字符数29。digui函数里没有使用这个返回值，也没有执行其他操作来覆盖它，于是这个值就在EAX寄存器里一直保留到了函数退出。 然后，这段代码是非法代码，在任何一个高级一点的编译器上都直接通不过编译！因为必须有返回值，这是语言标准规定的，跟是否使用EAX这个实现应该完全脱离关系。VC6.0是一个很方便的工具，但它实在太老了，要知道它诞生的时候不管是C99还是C++标准都还没有确定。所以别用它较真，否则倒霉的是你自己！ 充分证明： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！

引用 13 楼 xiaohuh421 的回复:你可以这样理解. 每递归一次, 函数名都增加一个序列号, 即你把递归想成每次调用的都是不同的函数,只是内部代码相同.  你调用一次函数, 肯定会执行到返回, 那么自然就会一层一层的返回了, 最终返回到外部调用的地方. 因为每次调用, 都会有压栈操作. 所以函数返回地址和参数都是在栈里面的.  利用这个原理, 你完全可以把递归转换成循环来做, 在某些栈递归层次过深, 会导致栈溢出的情况下, 这就可以解决. 正解

引用 12 楼 czarten 的回复:这个程序不对吧，else里面没有return 一般来说比较常见的递归格式是  int digui(int i) {         if(...)         {                 return ...;         }         else         {                 return digui(...);         } }   另外对递归过程的理解是纯粹的逻辑问题，就看能不能想明白，为此研究汇编实现没什么必要 觉得还是学学汇编吧！老师也挺建议我们学的。作为软件专业的学生

引用 19 楼 baichi4141 的回复:首先，很多返回值使用EAX寄存器来返回，所以在这个例子里，因为你没有指定返回什么数值，调用该函数的地方就自动把函数退出后EAX寄存器中残留的数值当做返回值了。也就是说，你函数中最后使用EAX寄存器来保存的是什么值，它就认为你返回了什么值。至于29是怎么来的——printf函数返回的是打印出的字符数29。digui函数里没有使用这个返回值，也没有执行其他操作来覆盖它，于是这个值就在EAX寄存器里一直保留到了函数退出。 然后，这段代码是非法代码，在任何一个高级一点的编译器上都直接通不过编译！因为必须有返回值，这是语言标准规定的，跟是否使用EAX这个实现应该完全脱离关系。VC6.0是一个很方便的工具，但它实在太老了，要知道它诞生的时候不管是C99还是C++标准都还没有确定。所以别用它较真，否则倒霉的是你自己！ 深入浅出

沒有返回值還是第一次見到這事情,越界就常見

引用 16 楼 zhao4zhong1 的回复:“给定一个小点的输入，完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门！ 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出 牛人啊！上次就是听了你的解答才下定决心学汇编

引用 10 楼 user-6 的回复:[quote=引用 9 楼 u012510962 的回复:] [quote=引用 7 楼 user-6 的回复:] [quote=引用 5 楼 u012510962 的回复:] 谢谢指教！！ 正是因为对c语言其中的不理解，现在正在自学《汇编语言》。 在我发这个帖子的时候我已经知道上面那个程序是存在问题的，因为函数在后面没有return，我只是没有明确上面那个递归函数是不是是自己默认返回一个值，返回是那个是随机取一个变量，还是与程序中的某些信息有关？ 嗯，学一下汇编还是有好处的，很多问题都可以根据生成的汇编码来理解。不过有一个问题要注意下，汇编码本身是否是跟实现本身有关的？就是说换一个环境，汇编码就不同了？学语言不应该去遵循实现来学习，应该按照提供的标准来学习。至于里面的一些难点疑惑，可以结合汇编的形式来解决。[/quote] 我也是刚开始学汇编的，对于汇编的环境什么的不大懂。您上面说的“就是说换一个环境，汇编码就不同了”指的是pc机16位、32位、和64位的环境吗？ “学语言不应该去遵循实现来学习”这点我是非常的同意，现在正是学习的时候不是要靠实现代码来完成任务。 “应该按照提供的标准来学习”提供的标准是指语言内在的规定，语言库中支持的语句吗？ 真的谢谢您的解答，在大学的学习道路上有你们这些前辈的指点真的胜过老师的十节课。[/quote] C/C++生成的汇编码跟32位机器、64位机器有关，也和编译器本身有关。不同的编译器生成的编译语句有关，有时候还会因为开优化选项而发生变化。  但是汇编和C/C++甚至其他编译语言都是息息相关，因为所有的编译代码最后都要转成机器语言，所以通过汇编的形式去了解这个语言也是一种形式。汇编可以有助于加深对语言的了解不假，但是首先要区分，哪些是因为编译器不同、环境不同造成的，如果你错误的把实现当做标准，可能在移植上会吃苦头。  给你举个最常见的例子，置顶贴里有一个例子，比如：int a=0;int i=(++a)+(a++)+(++a)，你能说下i的值是多少吗？你可以去利用汇编去了解，也可以通过其他方法去解释，但是标准里明确的说明这是未定义行为，其实现取决于编译器本身。所以你看到的汇编码，在不同的编译器下都是不同的。[/quote] 哦，首先谢谢您的详细讲解。您上面所要告诉我的是：不要把代码的实现当作标准去看，也不要认为反汇编后的汇编代码就是实现这个程序的标准形式，有时候根据环境的不同，相同的代码会反汇编出不同的汇编语句。在我们学习语言的同时汇编只是起到了辅助的作用，当我们不能理解代码的运行时可以看反汇编代码帮助我们更好的理解。

引用 9 楼 u012510962 的回复:[quote=引用 7 楼 user-6 的回复:] [quote=引用 5 楼 u012510962 的回复:] 谢谢指教！！ 正是因为对c语言其中的不理解，现在正在自学《汇编语言》。 在我发这个帖子的时候我已经知道上面那个程序是存在问题的，因为函数在后面没有return，我只是没有明确上面那个递归函数是不是是自己默认返回一个值，返回是那个是随机取一个变量，还是与程序中的某些信息有关？ 嗯，学一下汇编还是有好处的，很多问题都可以根据生成的汇编码来理解。不过有一个问题要注意下，汇编码本身是否是跟实现本身有关的？就是说换一个环境，汇编码就不同了？学语言不应该去遵循实现来学习，应该按照提供的标准来学习。至于里面的一些难点疑惑，可以结合汇编的形式来解决。[/quote] 我也是刚开始学汇编的，对于汇编的环境什么的不大懂。您上面说的“就是说换一个环境，汇编码就不同了”指的是pc机16位、32位、和64位的环境吗？ “学语言不应该去遵循实现来学习”这点我是非常的同意，现在正是学习的时候不是要靠实现代码来完成任务。 “应该按照提供的标准来学习”提供的标准是指语言内在的规定，语言库中支持的语句吗？ 真的谢谢您的解答，在大学的学习道路上有你们这些前辈的指点真的胜过老师的十节课。[/quote] C/C++生成的汇编码跟32位机器、64位机器有关，也和编译器本身有关。不同的编译器生成的编译语句有关，有时候还会因为开优化选项而发生变化。  但是汇编和C/C++甚至其他编译语言都是息息相关，因为所有的编译代码最后都要转成机器语言，所以通过汇编的形式去了解这个语言也是一种形式。汇编可以有助于加深对语言的了解不假，但是首先要区分，哪些是因为编译器不同、环境不同造成的，如果你错误的把实现当做标准，可能在移植上会吃苦头。  给你举个最常见的例子，置顶贴里有一个例子，比如：int a=0;int i=(++a)+(a++)+(++a)，你能说下i的值是多少吗？你可以去利用汇编去了解，也可以通过其他方法去解释，但是标准里明确的说明这是未定义行为，其实现取决于编译器本身。所以你看到的汇编码，在不同的编译器下都是不同的。

引用 7 楼 user-6 的回复:[quote=引用 5 楼 u012510962 的回复:] 谢谢指教！！ 正是因为对c语言其中的不理解，现在正在自学《汇编语言》。 在我发这个帖子的时候我已经知道上面那个程序是存在问题的，因为函数在后面没有return，我只是没有明确上面那个递归函数是不是是自己默认返回一个值，返回是那个是随机取一个变量，还是与程序中的某些信息有关？ 嗯，学一下汇编还是有好处的，很多问题都可以根据生成的汇编码来理解。不过有一个问题要注意下，汇编码本身是否是跟实现本身有关的？就是说换一个环境，汇编码就不同了？学语言不应该去遵循实现来学习，应该按照提供的标准来学习。至于里面的一些难点疑惑，可以结合汇编的形式来解决。[/quote] 我也是刚开始学汇编的，对于汇编的环境什么的不大懂。您上面说的“就是说换一个环境，汇编码就不同了”指的是pc机16位、32位、和64位的环境吗？ “学语言不应该去遵循实现来学习”这点我是非常的同意，现在正是学习的时候不是要靠实现代码来完成任务。 “应该按照提供的标准来学习”提供的标准是指语言内在的规定，语言库中支持的语句吗？ 真的谢谢您的解答，在大学的学习道路上有你们这些前辈的指点真的胜过老师的十节课。

引用 6 楼 user-6 的回复:给你看段，也就是函数返回值的问题：i=digui(d); 00D63A96  mov         eax,dword ptr [d]   00D63A99  push        eax   00D63A9A  call        digui (0D61429h)   00D63A9F  add         esp,4   00D63AA2  mov         dword ptr [i],eax //就是把eax的值写入i中从这里可以看出，return语句其实就是把需要return的值压入eax中，然后到调用的地方读取这个值。 因为printf本身也是一个函数调用嘛，所以你可以猜测下，调用了printf后eax的值改变了，应该是printf返回了一个值。写一句c=printf("i=%d\n    i is address=%d\n",i,&i); 然后printf("%d\n",c);看看就知道了。结果可以看出，c的值就是你返回给i值。  我查了下，printf()的返回值就是打印的字符串长度，你可以去验证下。 正如你所说的。谢谢啊！！

引用 5 楼 u012510962 的回复:谢谢指教！！ 正是因为对c语言其中的不理解，现在正在自学《汇编语言》。 在我发这个帖子的时候我已经知道上面那个程序是存在问题的，因为函数在后面没有return，我只是没有明确上面那个递归函数是不是是自己默认返回一个值，返回是那个是随机取一个变量，还是与程序中的某些信息有关？ 嗯，学一下汇编还是有好处的，很多问题都可以根据生成的汇编码来理解。不过有一个问题要注意下，汇编码本身是否是跟实现本身有关的？就是说换一个环境，汇编码就不同了？学语言不应该去遵循实现来学习，应该按照提供的标准来学习。至于里面的一些难点疑惑，可以结合汇编的形式来解决。

引用 3 楼 user-6 的回复:我问你个问题，比如这个函数 void swap(int a,int b){     int t=a;     a=b;     b=t; }  int main(){     ……     swap(a,b);     …… } 你觉得主函数调用了swap(a,b)之后回到那里了？当然是main调用swap的地方咯  当然，如果你说的是你的函数是一个有返回值的函数，但是里面却没有返回语句的话，或者说只有一条在if语句中的return语句的话。那么这个函数仍然可以执行，但是如果在java或者C#就会有一个error就是没有所有路径都有返回值。也就是说C++允许这种写法，但是会返回什么值要看编译器的实现了，具体看一下汇编嘛，应该是某个寄存器的残留值。这个的确是不合理的，你的想法是对的。 谢谢指教！！ 正是因为对c语言其中的不理解，现在正在自学《汇编语言》。 在我发这个帖子的时候我已经知道上面那个程序是存在问题的，因为函数在后面没有return，我只是没有明确上面那个递归函数是不是是自己默认返回一个值，返回是那个是随机取一个变量，还是与程序中的某些信息有关？

发现前面一半和你的问题有点无关，算了...

引用 1 楼 derekrose 的回复:有那么复杂吗？把你不懂的说的尽可能简单一点 不好意思，由于本人语言组织能力不大好，所以才写了这么多，麻烦大神费心花点时间看下。谢谢！！


Question: C语言之路，一路有你们，我很感谢。

为什么要用typedef？-- 就是因为要用下面的Ex这个“别名”来代替复杂的“struct Ex”(这里是一个整体)

引用 2 楼 u012804737 的回复:typedef struct Ex{   }Ex; 这不是有两个Ex 吗？ 这个是可以的，第一个是struct Ex，第二个Ex是struct Ex的简称。

引用 8 楼 Adol1111 的回复:这是两码事 而且typedef只是取别名而已，我把别名取成一样的难道就不行吗？谁规定别名就不能和原名相同了？ 更何况，C语言本身struct EX才是一个类型整体，我只是把整个类型struct EX取个EX的别名而已。   谢谢了，我明白了。

c里面 struct Ex和Ex是一样的，Ex和Ex是不一样的，c++里面都是一样的。

听大神们讲讲啊

不一样的！ 上面个人一般会习惯加上 _tag_Ex

引用 2 楼 u012804737 的回复:typedef struct Ex{   }Ex; 这不是有两个Ex 吗？  这是合法的，tag与id是两个不同的名称空间。

能成功编译吗？我没见过这种写法，不敢肯定，编译能过就没问题，书上也是有错误的。

那你的意思是这个例子是错的了？我是在C和指针这本书上照抄下来的。

上边那个Ex是不可以的，你一试就知道了。

typedef struct Ex{   }Ex; 这不是有两个Ex 吗？

哪有两个Ex


Question: 听了大神的意见，去看计组和单片机，然后对于寄存器有点问题，求指导~

（ROM或者RAM）

寄存器可以很复杂-----可以执行包括移位，各种位运算等等功能在内的计算， 也可以很简单----仅仅是一块存储器（ROM或者ROM）的一些单元  CPU的各种寄存器，一般都能够执行某些运算，一些芯片的寄存器，可能只是用来存储一些信息。 51的SFR，实际是一批不同功能的寄存器，地址在CPU内部的ram 位置的区域中。 A 累加器，B 辅助寄存器 R0~R8 *4 51 的通用寄存器组 另外还有一些专用寄存器，比如DPTR,PC，SP等等   寄存器，是芯片上，执行某些功能的一些单元，它至少有存储功能。  51 的寄存器，地址是在CPU内部的ram 位置的区域中。  X86 寄存器的地址，是不暴露给软件使用的； 软件里只能使用相应的指令，寻址寄存器，而不是通过寄存器的地址，使用寄存器。

这是要走纯硬件开发的路线啊

恩，勤奋学习，先学习好一款芯片

引用 11 楼 jerry_dqh 的回复:[quote=引用 10 楼 u010412073 的回复:]   [quote=引用 9 楼 worldy 的回复:] 51的AB寄存器确实是SFR，我记错了，不好意思，呵呵  现在微机的通用寄存器有 EAX EBX ECX EDX ESI EDI EBP ESP CS SS DS FS GS EIP EFLAGS 段描述符寄存器组、GDTR IDTR CR0 CR1....，太复杂了，你还是自己找一下资料，呵呵 嗯嗯，已经差不多清楚了，看了好多资料。[/quote] 好像淘宝上有开发用的芯片，开发版，还有资料送。试试看[/quote] 买块版可以送一堆....

引用 10 楼 u010412073 的回复:[quote=引用 9 楼 worldy 的回复:] 51的AB寄存器确实是SFR，我记错了，不好意思，呵呵  现在微机的通用寄存器有 EAX EBX ECX EDX ESI EDI EBP ESP CS SS DS FS GS EIP EFLAGS 段描述符寄存器组、GDTR IDTR CR0 CR1....，太复杂了，你还是自己找一下资料，呵呵 嗯嗯，已经差不多清楚了，看了好多资料。[/quote] 好像淘宝上有开发用的芯片，开发版，还有资料送。试试看

引用 9 楼 worldy 的回复:51的AB寄存器确实是SFR，我记错了，不好意思，呵呵  现在微机的通用寄存器有 EAX EBX ECX EDX ESI EDI EBP ESP CS SS DS FS GS EIP EFLAGS 段描述符寄存器组、GDTR IDTR CR0 CR1....，太复杂了，你还是自己找一下资料，呵呵 嗯嗯，已经差不多清楚了，看了好多资料。

引用 6 楼 AnYidan 的回复:SFR: Special Function Register  CPU 中的 registers 一般指 work register, PC register 等与 获取，解码，执行 instruction 相关的register 能说明下，在51中寄存器的分布和微机中寄存器的分布么？

引用 4 楼 worldy 的回复:51单片机的硬件结构和86(intel的体系架构)系列有比较大的差别，其内部ram集成在芯片内部，并将其中32字节用作寄存器(4个寄存器组)，只有AB寄存器是独立的  从结构角度，z80的架构和intel芯片比较接近（不恰当的比较，后者的性能和功能比前者高出不知道多少倍) AB属于SFR，也位于RAM中啊。。。。。

引用 3 楼 supermegaboy 的回复:你受人蛊惑，搞计算机组成原理是理解不了C的，两者不是相同层次上的东西。学好计算机组成原理有助于理解C的实现，但不是C本身，C语言根本不知道有CPU、内存、外部存储器等等这些东西。 其实也想学习硬件方面的知识。。

寄存器这个名词的范围比较宽泛，并没有绝对的一种定义，寄存器必须在哪里。  比较典型的：  1，一般处理器中的通用寄存器，在cpu内部的寄存器文件中，比如x86中的AX； 2，处理器内部一些专用寄存器，比如PC； 3，协处理器中的寄存器； 4，io空间或者存储空间映射的，处理器自定义的寄存器； 5，片内外设控制等寄存器； 6，外部总线连接的外部设备中的寄存器；  不同寄存器访问方式各不相同，功能千差万别，无法准确定义。  建议不要再钻牛角尖了。

我又来问问题了，表示没有太多的学习资料真的很受伤，然后，百度什么的没有找到这个，求各位大神帮忙解释下。


Question: 广义表NIL

引用 2 楼 qq921965140 的回复:[quote=引用 1 楼 N_sev7 的回复:] nil表示无值，任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真。 Objective-C, Ruby, Lua中的关键字，与C++里的NULL不同，NULL是一个宏定义，值为0，nil表示无值 任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真 ---------------百度百科拜托，我也会百度好不好，唉，感觉CSDN里的人都是为了加分不好好回答问题，没有学习的氛围。[/quote] 你觉得百度谷歌是干什么用的？ 我和你意见正好不一样 我最看不起那些有问题百度谷歌都不用下就直接问别人的人 谷歌百度跟翻书有很大区别吗？ 所有问题可以自己想想办法解决，不管是翻书还是上网搜 等你真正工作的时候就明白谷歌百度的重要性了

引用 3 楼 user-2 的回复:[quote=引用 2 楼 qq921965140 的回复:] [quote=引用 1 楼 N_sev7 的回复:] nil表示无值，任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真。 Objective-C, Ruby, Lua中的关键字，与C++里的NULL不同，NULL是一个宏定义，值为0，nil表示无值 任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真 ---------------百度百科拜托，我也会百度好不好，唉，感觉CSDN里的人都是为了加分不好好回答问题，没有学习的氛围。[/quote] ...你可以看看小版块中置顶贴提问的智慧，里面有一段是这样的：  运用某些策略，比如用谷歌（Google）搜索你遇到的各种错误提示（既搜索 谷歌论坛，也搜索网页）， 这样很可能直接就找到了解决问题的文档或邮件列表线索。 即使没有结果，在邮件列表或新闻组寻求帮助时提一句“我在谷歌中搜过下列句子但没有找到什么有用的东西” 也是件好事，至少它表明了搜索引擎不能提供哪些帮助。将搜索关键词与你的问题及可能的解决方案联系起来，还有助于引导其他有类似问题的人。  你根本没有明确的说出你不要百度或google的结果，那别人特地为你找了答案，你又说别人不好好回答。那你想怎样？想要更好的结果之前，你应该想想是否为他人想过，是否有明确的提出自己的意见，而不是因为找不到需要的答案就说别人的问题。 ———————————————— 不说这个话题了，NIL就是空表的意思，这点和NULL还是有差异的。NULL只是一个约定，表明这是一个空表的意思，而并非是一个真正的空表。就比如指针int *p=NULL,指向的是NULL这个位置，但不代表它没有值。 不过在C/C++里是没有这个类型的，所以你只能用NULL约定是一个空表，但在objective-C之类的语言中可以用NIL表示明确的无值。广义表的描述就是非计算机语言，所以NIL表示空表没什么问题。[/quote]好吧，看你码字那么多！

引用 2 楼 qq921965140 的回复:[quote=引用 1 楼 N_sev7 的回复:] nil表示无值，任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真。 Objective-C, Ruby, Lua中的关键字，与C++里的NULL不同，NULL是一个宏定义，值为0，nil表示无值 任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真 ---------------百度百科拜托，我也会百度好不好，唉，感觉CSDN里的人都是为了加分不好好回答问题，没有学习的氛围。[/quote] ...你可以看看小版块中置顶贴提问的智慧，里面有一段是这样的：  运用某些策略，比如用谷歌（Google）搜索你遇到的各种错误提示（既搜索 谷歌论坛，也搜索网页）， 这样很可能直接就找到了解决问题的文档或邮件列表线索。 即使没有结果，在邮件列表或新闻组寻求帮助时提一句“我在谷歌中搜过下列句子但没有找到什么有用的东西” 也是件好事，至少它表明了搜索引擎不能提供哪些帮助。将搜索关键词与你的问题及可能的解决方案联系起来，还有助于引导其他有类似问题的人。  你根本没有明确的说出你不要百度或google的结果，那别人特地为你找了答案，你又说别人不好好回答。那你想怎样？想要更好的结果之前，你应该想想是否为他人想过，是否有明确的提出自己的意见，而不是因为找不到需要的答案就说别人的问题。 ———————————————— 不说这个话题了，NIL就是空表的意思，这点和NULL还是有差异的。NULL只是一个约定，表明这是一个空表的意思，而并非是一个真正的空表。就比如指针int *p=NULL,指向的是NULL这个位置，但不代表它没有值。 不过在C/C++里是没有这个类型的，所以你只能用NULL约定是一个空表，但在objective-C之类的语言中可以用NIL表示明确的无值。广义表的描述就是非计算机语言，所以NIL表示空表没什么问题。

引用 1 楼 N_sev7 的回复:nil表示无值，任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真。 Objective-C, Ruby, Lua中的关键字，与C++里的NULL不同，NULL是一个宏定义，值为0，nil表示无值 任何变量在没有被赋值之前的值都为nil，对于真假判断，只有nil与false表示假，其余均为真 ---------------百度百科拜托，我也会百度好不好，唉，感觉CSDN里的人都是为了加分不好好回答问题，没有学习的氛围。


Question: 关于c语言的结构体

typedef除了少打几个字，没啥好处，当然，对一些复杂类型，用typedef定义个别名也有些好处，变得更清晰

二楼正解啊··

引用 4 楼 max_min_ 的回复:两种都可以的！个人编码风格不同而已！ 我用下面一种居多！ re

两种都可以，没有区别，习惯而已

为什么有的代码里会同时存在这两种定义呢?  同时存在的话，不加命名空间，肯定会报：变量已经定义的错误。

个人写法不同吧，我的理解是主要在typedef上  typedef  [已有类型名] [新类型名]  第一种就是先定义类型，然后根据新的类型名再定义新的类型名 第二种可以把中间的结构体定义看作一个整体，也就像当于一个类型名喽，其实都是一样一样滴

c语言的话 第二种编译可以通过吗

两种都可以的！个人编码风格不同而已！ 我用下面一种居多！

可能是不同人写得吧

两个结构体相互指向的时候，用typdef  结构体里面包含指向自身类型的指针时，用typdef  还有就不知道了

typedef struct{     type data; }name_t，*name_p;  name_t st; 定义一个名为 st 结构变量。 name_p sp; 定义一个名为 sp 指针变量  标准用法。其他用法，自行理解。


Question: C文件操作，结构体

不错的云代码

貌似简单循环fscanf即可...

引用 引用 5 楼 liuchunruiYJDWANN 的回复:简单实现如下： #include <stdio.h> #define N 1024 void main() { 	FILE *fp; 	char str[N]; 	int a; 	char temp[50]; 	int k=0; 	fp=fopen("D:\\1.txt","r"); 		if(fp!=NULL) 		{  			fgets(str,N,fp);//先放入str数组中 		} 		for(int i=0;str[i]!='\0';i++)//对数组进行处理 		{ 			if(str[i]!=' '&&str[i]!=',') 				{ 					if(str[i]>'0'&&str[i]<'9') 					{ 						a+=str[i]-'0'; 				 					} 					else  					temp[k++]=str[i]; 					printf("%c",str[i]); 				} 			else 			if(str[i]==' ') 				{ 					temp[k]='\0'; 					//可以把用copy函数给结构体中的city赋值 					//把a赋值给结构体中的number 					a=0; 				} 			 			 		} } 用我们数据结构老师的话说，你这个算法确实行得通，不过也太笨了。读过来还要这么那么。用fscanf(fp,"type_t",type_tname);还可以读到我的结构体struct citynode{   char city[20];int citynum;};里面。这个不是省好多事哦 不过，谢谢啦哈。麻烦麻烦了。cout<<"Thanks a lot\n";

引用 引用 7 楼 angel_su 的回复:貌似简单循环fscanf即可...说得太撇托了，不过我还真的是用的这个函数，自己搞出来了。

引用 4 楼 u012540439 的回复:引用  [quote=引用 3 楼 jerry_dqh 的回复:] 读取文件 std::vector<char> v; if (FILE *fp = fopen("filename", "r")) { 	char buf[1024]; 	while (size_t len = fread(buf, 1, sizeof(buf), fp)) 		v.insert(v.end(), buf, buf + len); 	fclose(fp); }[/quote] 嚄……我学的是.h头文件格式，std::这个还真有点不明白;不过我问的是，拿第一个城市的文件说，欲读取”北京“到我定义的结构体的为字符型变量city里面，0到结构体的int number里面；然后每个逗号后面的内容都如此放在结构体struct node【i】中.怎么弄好？[/quote]  逐条读入记录（逗号分割） 每条记录中以 空格分割不同的 item 重复直至读入所有记录

引用 引用 3 楼 jerry_dqh 的回复: 读取文件 std::vector<char> v; if (FILE *fp = fopen("filename", "r")) { 	char buf[1024]; 	while (size_t len = fread(buf, 1, sizeof(buf), fp)) 		v.insert(v.end(), buf, buf + len); 	fclose(fp); }[/quote] 嚄……我学的是.h头文件格式，std::这个还真有点不明白;不过我问的是，拿第一个城市的文件说，欲读取”北京“到我定义的结构体的为字符型变量city里面，0到结构体的int number里面；然后每个逗号后面的内容都如此放在结构体struct node【i】中.怎么弄好？

引用 2 楼 u012540439 的回复:引用用C语言中的文件读取学得不好，敲两个代码示范一下？ 读取文件 std::vector<char> v; if (FILE *fp = fopen("filename", "r")) { 	char buf[1024]; 	while (size_t len = fread(buf, 1, sizeof(buf), fp)) 		v.insert(v.end(), buf, buf + len); 	fclose(fp); }

引用用C语言中的文件读取学得不好，敲两个代码示范一下？

用C语言中的文件读取


Question: PE文件导入表的问题

可以看看这里 http://bbs.bccn.net/thread-226658-1-1.html printf("%x\n",MessageBoxA);就是实际地址

虚拟地址-载入内存后的地址  Pe文件有一个Import address table  当调用api的时候,push所有的参数后,就跳到这个表call [4019f8]  这个表上面写着4019f8 JMP DWORD PTR DS:[405188]  405188是一个指针,里面存着Messagebox在user32里面的地址  而JMP DWORD PTR DS:[405188]这条命令的意思就是,获取405188指针的内容(messagebox在user32里的地址),然后跳到那里.

引用 3 楼 user-2 的回复:用od看一下被,  PROC pr = (PROC)MessageBoxA得到的地址 4019f8 这个是程序运行后MessageBoxA在IAT表里的位置 4019f8 JMP DWORD PTR DS:[405188]  405188里面存着指向user32.dll的指针 你好，这里我确实有点不清楚 405188是相对于dll模块的地址还是相对于进程地址空间的地址？

引用 1 楼 toofunny 的回复:先说说你的导入表是怎么解析出来的？ 如果是自己动态解析的，那就是编程错误。 如果是用工具静态解析的，请复习PE知识。 	HMODULE hModule = GetModuleHandle(NULL); 	PROC pr = (PROC)MessageBox; 	 	printf("PROC pr = (PROC)MessageBoxA得到的地址     %x\n",pr); 	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hModule;    //定位dos文件头  	 	 	IMAGE_OPTIONAL_HEADER* pOptHeader = (IMAGE_OPTIONAL_HEADER*) 	((BYTE*)hModule+pDosHeader->e_lfanew+24); 	 	IMAGE_IMPORT_DESCRIPTOR* pImport=(IMAGE_IMPORT_DESCRIPTOR*) 	((BYTE*)hModule+ 	pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);  	//定位导入表     while(pImport->FirstThunk){     	buffer = (char*)((BYTE*)hModule+pImport->Name);     	printf("加载的DLL名为 %s\n",buffer);     	IMAGE_THUNK_DATA* pThunk=(IMAGE_THUNK_DATA*) 		((BYTE*)hModule+pImport->OriginalFirstThunk); 		 		while(pThunk->u1.Function){ 			function_name = (char*)((BYTE*)hModule+(DWORD)pThunk->u1.AddressOfData+2); 			PDWORD pAddr = (DWORD*) 			((BYTE*)hModule+pImport->FirstThunk)+k; 			printf("函数名为    %s",function_name); 			printf("        函数地址    %x\n",pAddr); 			k++; 			pThunk++; 		}     	pImport++;     }


Question: 2维数组的疑惑

1楼正   解

(int (*)[COLSIZE]) malloc .......

int (*pA)[COLSIZE] =(int( *)[COLSIZE]) malloc(sizeof(int) * ROWSIZE * COLSIZE);  加一个括弧就好了。 int (*)[]括弧是语法的一部分。


Question: 一个简单的指针问题

谢谢大家的帮忙 小弟分少，抱歉了

引用 11 楼 wanren13 的回复:谢谢大家的帮忙，之前的问题已经解决，现在又有了新问题       NUM_OF_CARD = 52;   NUM_NUM = 13;   SUITS_NUM = 4;    const char *suits[] = {"Clubs\0", "Diamonds\0", "Hearts\0", "Spades\0"};   const char *numbers[] = {"A\0", "2\0", "3\0", "4\0", "5\0", "6\0", "7\0",                     "8\0", "9\0", "10\0", "J\0", "Q\0", "K\0"};   static char *cards[NUM_OF_CARD];    int i, s, n;    for (i = 0; i < NUM_OF_CARD; i++){     s = i / NUM_NUM;     n = i / SUITS_NUM;     strcpy(cards[i], suits[s]);     strcat(cards[i], " ");     strcat(cards[i], numbers[n]);   }   为什么会有segmentation fault?? 这个是指针错误，你看下指针部分的。。。你的cards[i]是一个字符串指针，相当于你用一个char *string;strcpy(string,suits[s]);这个当然会报错，你只有一个指针，并没有空间来存放字符串的。

引用 楼主 wanren13 的回复:以下代码问题到底出在哪？该如何解决？   char **suits = {"clubes\0",  "Diamonds\0", "Hearts\0", "Spades\0"}; //这里需要加\0吗？  for (i = 0; i < sizeof(suits); i++){     printf("%s ", suits);     suits++;   }  {}这种初始化方式用于数组初始化。

char *suits[]或者char* suits[]，表示suits是一个数组，数组元素的类型是char*

sizeof(suits) 得到的是指针的大小为4吧， for (i = 0; i < sizeof(suits); i++){     printf("%s ", suits);     suits++;    } 输出会乱了吧

数组在使用时，数组名可以隐式转化为指向第一个元素的指针 如果你因为这个隐式转换就以为数组和指针是同一种东西，我只能说请从头复习基础知识

引用 5 楼 wanren13 的回复:[quote=引用 4 楼 u012348978 的回复:] char **suits 这只是一个指针变量。  他不是指针数组，你不能这样赋值。  这样。char *suits[] = {"clubes\0",  "Diamonds\0", "Hearts\0", "Spades\0"};   指针是一种强类型，对类型的要求非常严格。所以认识指针是一个漫长的过程，心急不得。  没改之前还能显示第一个string。。。 改完连一个都显示不出来了。。。 而且还有segmentation fault。。。[/quote]  char *suits[] = {"clubes\0",  "Diamonds\0", "Hearts\0", "Spades\0"}; //这里需要加\0吗？     for (int i = 0; i < 4/*这个指针学得不好，没有想出一个动态计算的办法*/; i++){     printf("%s ", suits[i]);     //suits++;这是一个数组，所以是一个，把指针保存到指针的错误     }

引用 4 楼 u012348978 的回复:char **suits 这只是一个指针变量。  他不是指针数组，你不能这样赋值。  这样。char *suits[] = {"clubes\0",  "Diamonds\0", "Hearts\0", "Spades\0"};   指针是一种强类型，对类型的要求非常严格。所以认识指针是一个漫长的过程，心急不得。  没改之前还能显示第一个string。。。 改完连一个都显示不出来了。。。 而且还有segmentation fault。。。

引用 1 楼 user-8 的回复: char *suitsp[] = {"clubes\0",  "Diamonds\0", "Hearts\0", "Spades\0"};   *suits[] 和 **suits 有什么区别？？？

1.这样初始化的话  应该也可以吧，用\0吗 取决于你用里面的字符串干什么，printf %s是怎么处理字符串的 2.sizeof的用法不对


Question: 队尾指针丢失

引用 7 楼 angel_su 的回复:没那句if的话，自然是发生你顶楼说的那个问题...为什么你们都那么含蓄，就是不肯说“指针悬挂”这四个字。算了，累觉不爱，结贴。

没那句if的话，自然是发生你顶楼说的那个问题...

引用 5 楼 angel_su 的回复:if (Q.rear = = p)  Q.rear = Q.front; 代码里判断处理了，没问题的没这句代码的话，rear是不是悬挂指针？唉，问个问题咋就那么难呢？

引用 3 楼 user-2 的回复:[quote=引用 2 楼 qq921965140 的回复:] [quote=引用 1 楼 user-2 的回复:]  free (p);  p =NULL; //悬挂指针也就是野指针，有地址，但是不知道指向什么地方！  我想知道这里队尾指针是属于指针悬挂吗？[/quote]  1 你的队尾指针的指向你知道么？   2 == 中间不要空格了 [/quote] 是不是？求大神一个准确的回答，不要那么含蓄嘛。代码是我拷的，没检查。

引用 2 楼 qq921965140 的回复:[quote=引用 1 楼 user-2 的回复:]  free (p);  p =NULL; //悬挂指针也就是野指针，有地址，但是不知道指向什么地方！  我想知道这里队尾指针是属于指针悬挂吗？[/quote]  1 你的队尾指针的指向你知道么？   2 == 中间不要空格了

引用 1 楼 user-2 的回复: free (p);  p =NULL; //悬挂指针也就是野指针，有地址，但是不知道指向什么地方！  我想知道这里队尾指针是属于指针悬挂吗？


Question: 指针数组的赋值

那是不是说有两种方法 1.先定义一个二维数组b【10】【7】，然后把a[i]=b[i]；这样？ 2.先分配内存，然后一个一个赋值，是*a[1]++这样把a里面的每个指针都这样一个一个的复过去？ 哪种效率高

引用 3 楼 susuding77 的回复:这样，原来的程序是b指向数组c,现在想在外层加一层循环，使的外层循环的指针数组，指向内层的b，当然内层的数组c的内容是每次都变化的。这个要怎样实现呢，有代码吗 需要给a[10]分配内存空间的！然后一个一个的赋值吧！ 不能通过地址来直接操作的！

是a每个都保存一个c的整个数组，c整个数组的值是每次循环都变化的。 就是一个二维数组c[10][7];想让a[i]=c[i].但是不想把c写成2为数组，只是想吧他作为一个一维数组的中间变量，每次都能把他的内容存下来

没看懂你的意思。 你是想a[0]-a[9]每一个都是保存整个数组c的地址：a[0]=c,a[1]=c…… 还是想a[0]保存c[0]的地址，a[1]保存c[1]的地址。a[0]=&c[0],a[1]=&c[1]……

不对！你是通过地址取值的！过程中可能是过程中的某一个组数值， 但是循环换了应该值剩下最后一组了！而且a[i]的指向都是相同的！指向同一块内存地址


Question: 指向数组的指针赋值

楼上说的对，加错位置后果很严重

...楼主看仔细啊，一个小错误有时候会需要几十倍的时间去排除错误。

刚才把++放前面了前面赋值的地方，所以打出来不一样，发帖的时候改成了现在的样子，搞错了，版主见谅

#include <iostream> using namespace std;  int main(void) {     int a[10]={3,7,53,2,3,6,7,3};     int *b;      b=a;     for (int i=0;i<10;i++)     {            *b=i*2+7;          cout<<*b<< " ";         cout<<a[i]<<endl;          b++;     }        return 0; }  //结果： 7 7 9 9 11 11 13 13 15 15 17 17 19 19 21 21 23 23 25 25  //疑惑在那里？


Question: bresenham画线算法求助

你这个代码哪里来的。 有问题吧  至少直线方向是靠近水平还是垂直 要分开处理吧。

印象中需要分8个角度范围即每个象限分两部分 分别处理。

引用 3 楼 relaxisland 的回复:你这个代码哪里来的。 有问题吧  至少直线方向是靠近水平还是垂直 要分开处理吧。/*compute the direction of the increment,an increment of O means either a vertial or horizontal line*/ if(delta_x>0) incx=1; else if(delta_x==0) incx=0; else incx=-1;  if(delta_y>0) incy=1; else if(delta_y==0) incy=0; else incy=-1;这一段不就是讨论垂直水平问题吗

引用 1 楼 N_sev7 的回复:     xerr+=delta_x;     yerr+=delta_y;  每一次循环着两个值都是增加？是不是这里？ 还没祥看代码 可以说是吧，主要就是xerr和yerr的变化，最后两个if循环没弄明白。


Question: 请教用C编写的菜单中，一个变量为啥不能被输入值？

引用 1 楼 user-1 的回复:char也可以，int也可以。不过char类型对应的是ascii，int类型对应的是数值，两者会有差异，最好统一下。  至于为什么没执行是因为你这句打错了：scanf("&d",&n);应该是：scanf("%d",&n);  你n没有输入，直接把你的第一个输入赋给后面的itemSelected。你单步调试下就知道了，他的确进入了相应的函数。但因为n没输入是一个垃圾值，所以如果系统给的n<0的话你这句：for (i=0;i<n-1;i++)就无法执行了，看上去就没有执行一样。  谢谢user-1，是我疏忽的一个小错误，哈


Question: %p和%x有什么区别吗？

引用 4 楼 max_min_ 的回复:%p打印地址的啊！ %x十六进制形式打印  完成不同！  %p void *; print as a pointer (implementation-dependent representation).

引用 4 楼 max_min_ 的回复:%p打印地址的啊！ %x十六进制形式打印  完成不同！版主解释的到位！谢谢~

%p 标准没有格式的规定, 打印出来像 0x%x  0X%08X  %08X 啥格式的都有...

引用 楼主 abc594986308 的回复:#include <stdlib.h> #include <stdio.h> int main() {     unsigned int *p;     p = (unsigned int *)malloc(100);     if(p)          printf("Memory Allocated at: %x",p);     else          printf("Not Enough Memory!\n");     getchar();     p = (unsigned int *)realloc(p,156);     if(p)          printf("Memory Realloc at: %x",p);     else          printf("Not Enough Memory!\n");     free(p);     getchar();     return 0;                      } 在linux下编程有警告。 realloc.c: In function ‘main’: realloc.c:8:10: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘unsigned int *’ [-Wformat=]           printf("Memory Allocated at: %x",p);           ^ realloc.c:14:10: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘unsigned int *’ [-Wformat=]           printf("Memory Realloc at: %x",p); 但是用%p后可以解决，我想问下%p和%x有什么区别么？ 没什么区别，结果上，唯一的区别的编译器警告的问题

%p打印地址的啊！ %x十六进制形式打印  完成不同！

64位下结果会不一样，老实点用%p吧...

区别就是 %p 相当于 0x%x

p打印指针,x打印整数.  printf("Memory Realloc at: %x",p); 改成下面应该也能消除 printf("Memory Realloc at: 0x%x",(unsigned int)p);


Question: 求助！！！求大神看看这个用数组求n！阶乘的函数错在哪里啊！1

引用 2 楼 u012912202 的回复:如果阶乘很大就不能用这种方法啊 大数阶乘没办法的，肯定会溢出的。 要么看看这个，大数的阶乘算法。

如果阶乘很大就不能用这种方法啊

#include<stdio.h>  #define P 600 int a[P]; int main() {     int n;     int i;      printf("input n:\n");     scanf("%d",&n);      a[0]=1;     printf("0 factorial value : %d", a[0]);     for (i=1;i<=n;i++)     {         a[i] = a[i-1]*i;         printf("%d factorial value : %d", i, a[i]);             }     return 0; }


Question: 有没有可能实现多行并行写入文件呢

引用 9 楼 caozhy 的回复:[quote=引用 8 楼 lm_whales 的回复:] 1）PC 机，似乎不可以：    大部分 PC硬盘接口类型决定，只能串行写，即使用两个磁盘。    另外PC机，即使SCSI接口硬盘，也是串行写。  2）SCSI接口的硬盘阵列似乎可以（多用于服务器）    同一块，硬盘只能串行写，    即使并行可以适当加速，也意义不大（基本上等同于没有加速）。  就lz的问题而言，RAID也是不可以。  注意，RAID并非按照字节交错或者并行存储到几个磁盘上，而是按照区块来的。一般典型的是128KB或者更大。[/quote] ++ 这个应用数据确实太少了，并行实在没有必要！

建议不要做这种无用功了。 操作系统往磁盘上写文件本来就是带内存缓冲写的。  在文件大小相同的前提下：  读刚读过的文件比头次读没读过的文件快  读转速快的硬盘上的文件比读转速慢的硬盘上的文件快  读没有磁盘碎片的文件比读有磁盘碎片的文件快  读文件不处理比边读边处理快  单线程从头到尾一次读文件比多线程分别读文件各部分快（非固态硬盘上）  读固态硬盘上的文件比读普通硬盘上的文件快 写文件也类似。

引用 8 楼 lm_whales 的回复:1）PC 机，似乎不可以：    大部分 PC硬盘接口类型决定，只能串行写，即使用两个磁盘。    另外PC机，即使SCSI接口硬盘，也是串行写。  2）SCSI接口的硬盘阵列似乎可以（多用于服务器）    同一块，硬盘只能串行写，    即使并行可以适当加速，也意义不大（基本上等同于没有加速）。  就lz的问题而言，RAID也是不可以。  注意，RAID并非按照字节交错或者并行存储到几个磁盘上，而是按照区块来的。一般典型的是128KB或者更大。

这样做没意思，不如先放内存缓存一下，一次写入文件效率高来

小心线程琐

当然可以，只要控制好每个线程在写文件时各自的起始位置即可。 但正如楼上所说，实际上写入数据时到操作系统这一层每个线程是排队一个一个的写入，所以最终还是串行的，效率只减不增

这样做只会更慢。因为硬盘只有一个磁头（对于每个盘片），所谓并行，最终还是串行的。

可以是可以的！但是得看你的电脑硬件了！ 如果是多核的话，则支持多个线程同时并行工作！如果是单核的话，就是多个线程轮询了！ 至于你的写文件，这里还是一个线程吧！因为写同一个文件的话，防止覆盖还是得加读写锁的！

引用 楼主 u011962366 的回复:比如一个二维数组a[10][100]；写入文件的时候总共是十行数据，有没有可能创建十个线程，每个线程负责一行数据的写入。做到十行数据同时写入同一个文件。  比copy mp3 的数据量小吧

不要认为多线程一定会提高工作效率，对于单线程处理器，往往很多时候看着是并行，实际还是一个一个换着来，反而有线程切换开销


Question: C 语句转换问题

？（GPIO_TypeDef *)是强制转换，对一个地址进行？以前都是对一个变量时行的。此处怎么理解？  (GPIO_TypeDef *) 这个强转是 指针类型的  你那个是地址 就是以你那个GPIOA_BASE为首地址 访问内存数据的方式就是以GPIO_TypeDef 结构体去看 GPIO_TypeDef *p;  p = GPIOA; 和这个写法类似吧 struct A { int a; int b; } struct A  * p; p = (struct A*)0x4000000;  不就是强转下吗 地址0x400000可能默认是按void *访问的  int a = 0x11223344; char answer; char *p = &answer; p = (char *)&a; 就是从a的地址开始看 以char类型读出来

不懂，帮顶，帮顶

test.c#include <stdio.h>  #include <stdlib.h>  typedef struct{                   short a;                   char b;                 }typedefaddress;  #define address  0x6000 0000  #define addr  ((typedefaddress*)address)  int main(int argc, char *argv[])  {           addr->a=22;      printf("%d\n",(*addr).a)      system("PAUSE");       return 0;  } VC6编译通过。

#include <stdio.h> #include <stdlib.h> typedef struct{                  short a;                  char b;                }typedefaddress; #define address  0x6000 0000 #define addr  ((typedefaddress*)address) int main(int argc, char *argv[]) {         addr->a=22;     printf("%d\n",(*addr).a)     system("PAUSE");	     return 0; }  那我这样写怎么编译通不过，报错在addr->a=22;

GPIOA_BASE是个32位地址（0X40000000).注意这个地址不是内存地址而是端口地址。

#define GPIOA  ((GPIO_TypeDef *) GPIOA_BASE) 这句话是什么意思啊？ （GPIO_TypeDef *)是强制转换，对一个地址进行？以前都是对一个变量时行的。此处怎么理解？  其中GPIOA_BASE是个32位地址（0X40000000). GPIO_TypeDef是一个结构体的类形。 --------------- #define GPIOA  ((GPIO_TypeDef *) GPIOA_BASE) 这句话是什么意思啊？ 1) 这句话的意思是把0X40000000这个地址当做结构体GPIO_TypeDef的首地址,即0X40000000开始的地址存储的是GPIO_TypeDef类型的数据.以此类型进行访问. 这种方式在驱动开发中非常常见.  （GPIO_TypeDef *)是强制转换，对一个地址进行？以前都是对一个变量时行的。此处怎么理解？ 2)变量在c语言中是symbol,它只是地址的标示,便于程序员操作.实际的指针转化操作都是直接对地址的.


Question: 听说大神都在夜晚出没！！关于结构体指针交换问题！！

引用 17 楼 Adol1111 的回复:[quote=引用 16 楼 qq695181966 的回复:] 我知道你们说的。 但是为什么我定义了struct data*t之后 令t=4 之后的交换也会出错呢？！ 自己随意指定的地址仍然是非法的。就好比你不给指针分配值，那指针就没有指向的地址吗？显然是不对的。 C/C++不存在所谓的无值对象，也就是Objective-C里的NIL类型，所以指针都是有值的。 那为什么仍然无法访问？很简单，计算机只是锁住了这个内存，除非你建立了一个对象，或者向系统申请一块空间，这个时候系统就会打开这块空间的使用权，那你就能正常访问了。 但是，系统打开了使用权，却不是这个指针的默认地址，而是取了一个新的地址，然后又赋给了你。所以你根本就不可能知道计算机的有效地址在哪里，因此t=4 99%是非法的。  你要么malloc一块地址，即像系统申请，要么就不要用指针了。这里其实用struct data t是最好的。没必要用什么指针：struct data t=*(p+i); *(p+i)=*(p+j); *(p+j)=t;[/quote]很谢谢耐心的指教！！早已解决！ 但是忘记结贴了！

谁告诉你大神都在夜间出没的？

引用 16 楼 qq695181966 的回复:我知道你们说的。 但是为什么我定义了struct data*t之后 令t=4 之后的交换也会出错呢？！ 自己随意指定的地址仍然是非法的。就好比你不给指针分配值，那指针就没有指向的地址吗？显然是不对的。 C/C++不存在所谓的无值对象，也就是Objective-C里的NIL类型，所以指针都是有值的。 那为什么仍然无法访问？很简单，计算机只是锁住了这个内存，除非你建立了一个对象，或者向系统申请一块空间，这个时候系统就会打开这块空间的使用权，那你就能正常访问了。 但是，系统打开了使用权，却不是这个指针的默认地址，而是取了一个新的地址，然后又赋给了你。所以你根本就不可能知道计算机的有效地址在哪里，因此t=4 99%是非法的。  你要么malloc一块地址，即像系统申请，要么就不要用指针了。这里其实用struct data t是最好的。没必要用什么指针：struct data t=*(p+i); *(p+i)=*(p+j); *(p+j)=t;

ft，csdn请告诉我，为啥quote和加颜色不能嵌套。。。  for(j=i+1;j<len;j++)

引用 楼主 qq695181966 的回复:void sortdata(struct data *p,int len) { 	int i,j; 	struct data *t;	 	for(i=0;i<len;i++) 	{ 		for(j=i+1;j<len;j++) 		{ 			if((p+i)->sum<(p+j)->sum) 			{ 				*t=*(p+i); 				*(p+i)=*(p+j); 				*(p+j)=*t; 			} 		} 	} 	for(i=0;i<len;i++,p++) 	{ 		printf("number:%d\t",p->number); 		printf("name:%s\t",p->name); 		printf("chinese:%.1f\t",p->chinese); 		printf("math:%.1f\t",p->math); 		printf("english:%.1f\t",p->english); 		printf("sum:%.1f\n",p->sum); 	} } 这个是我编写的程序中的一小段 我想进行以sum给标准的升序排序。但是为什么如果if（）内的条件满足了运行交换语句程序就报错了呢 这是我设置断点得到的错误提示：  红色这行的问题

引用 16 楼 qq695181966 的回复:[quote=引用 12 楼 max_min_ 的回复:]  struct data *t;    //没有分配内存空间！使用的有内存出错的问题阿！  struct data *t = (struct data *)malloc(sizeof(struct data)); 引用 13 楼 baichi4141 的回复:struct data *t;  请问，此时t指向内存中的什么位置？ 不知道，就别用。 我知道你们说的。 但是为什么我定义了struct data*t之后 令t=4 之后的交换也会出错呢？！[/quote] 像你主楼定义这样呢？没有空间的！要额外申请空间，然后再赋值操作 搞一本基础的书籍，补下基础，重点指针这块！

引用 16 楼 qq695181966 的回复:我知道你们说的。 但是为什么我定义了struct data*t之后 令t=4 之后的交换也会出错呢？！ 你知道“定义”和“申请内存”的区别？

引用 3 楼 derekrose 的回复:这问题不需要大神，我就能解决了  +1

引用 12 楼 max_min_ 的回复: struct data *t;    //没有分配内存空间！使用的有内存出错的问题阿！  struct data *t = (struct data *)malloc(sizeof(struct data));  一针见血

*t t =？？？？？？

还有，有malloc的地方，用完一定要手动free，不然会内存泄漏的。

引用 7 楼 qq695181966 的回复:引用 1 楼 user-10 的回复:指针变量t没有分配空间我在sortdata中定义了结构体指针t之后 令*t=4也出现这样的错误呀struct data a; struct data *t; t=&a;//引用有效地址 t=(struct data*)malloc(sizeof(struct data));//分配有效内存直接用*t=4是非法的。

引用 12 楼 max_min_ 的回复: struct data *t;    //没有分配内存空间！使用的有内存出错的问题阿！  struct data *t = (struct data *)malloc(sizeof(struct data)); 引用 13 楼 baichi4141 的回复:struct data *t;  请问，此时t指向内存中的什么位置？ 不知道，就别用。 我知道你们说的。 但是为什么我定义了struct data*t之后 令t=4 之后的交换也会出错呢？！

引用 3 楼 derekrose 的回复:这问题不需要大神，我就能解决了 哈哈哈 知道我不知道的知识的都是大神！ 嘻嘻~~

引用 4 楼 worldy 的回复:void sortdata(/*struct*/ data *p,int len) { 	int i,j; 	/*struct*/ data t;	 	for(i=0;i<len;i++) 	{ 		for(j=i+1;j<len;j++) 		{ 			if((p+i)->sum<(p+j)->sum) 			{ 				t=*(p+i); 				*(p+i)=*(p+j); 				*(p+j)=t; 			} 		} 	} //sort就sort，打印这些干嘛？ 	for(i=0;i<len;i++,p++) 	{ 		printf("number:%d\t",p->number); 		printf("name:%s\t",p->name); 		printf("chinese:%.1f\t",p->chinese); 		printf("math:%.1f\t",p->math); 		printf("english:%.1f\t",p->english); 		printf("sum:%.1f\n",p->sum); 	} }sort了之后printf出来啊

引用 7 楼 qq695181966 的回复:引用 1 楼 user-10 的回复:指针变量t没有分配空间我在sortdata中定义了结构体指针t之后 令*t=4也出现这样的错误呀  关键不是你在哪里定义，而是定义指针变量后必须给它分配空间后才能往里面写内容，空间都没有，内容要写到哪儿


Question: 请教个操作本地文件地址的问题，谢谢

参考http://blog.csdn.net/selina6874/article/details/6784697  引用 楼主 zhuoxuan216 的回复:如何对多个本地地址进行操作，操作原则是：根据地址最后一个\后的文件名进行，看文件名是否相同，相同记录一次，计数加一。然后输出文件名和计数。请问这个问题怎么实现呢

msdn, 查FindFirstFile， 或CFileFind类 有详细例子


Question: 急求Kruskal 算法的代码？？？

结贴.....

http://blog.csdn.net/niushuai666/article/details/6689285  百度上很多啊

http://blog.csdn.net/china_zoujinyong/article/details/16833293  我的博客 如果有什么问题随时留言


Question: 这是连接哪2个链表啊？

引用 1 楼 user-2 的回复:纠正一处错误：12行应该是 if(tmp == NULL) 嗯，确实写错了，谢谢斑竹

代码有些拼写错误，改正后如下： #include "stdlib.h" #include "stdio.h" struct list {    int data;    struct list *next; }; typedef struct list node; typedef node *link; link delete_node(link pointer,link temp) {    if(temp=NULL)       return pointer->next;    else       {          if(temp->next->next==NULL)             temp->next=NULL;          else             temp->next=temp->next->next;          return pointer;       } } void selection_sort(link pointer,int num)   { 	  link tmp,btmp;    int i,min;    for(i=0;i<num;i++)    {       tmp=pointer;       min=tmp->data;       btmp=NULL;       while(tmp->next)       {            if(min>tmp->next->data)            {                min=tmp->next->data;                btmp=tmp;            }            tmp=tmp->next;       } 		printf("\40: %d\n",min); 		pointer=delete_node(pointer,btmp);   } } link create_list(int array[],int num) {    link tmp1,tmp2,tmp3;    int i;    link pointer;    pointer=(link)malloc(sizeof(node));    pointer->data=array[0];    tmp1=pointer;    for(i=1;i<num;i++)    {        tmp2=(link)malloc(sizeof(node));        tmp2->next=NULL;        tmp2->data=array[i];        tmp1->next=tmp2;        tmp1=tmp1->next;    } return pointer; } link concatenate(link pointer1,link pointer2) {    link tmp;    tmp=pointer1;    while(tmp->next)       tmp=tmp->next;    tmp->next=pointer2;    return pointer1; } void main() {    int arr1[]={3,12,8,9,11};    link ptr;    ptr=create_list(arr1,5);    selection_sort(ptr,5); }

delete_node(link pointer,link temp)函数中temp是当前最小结点的前驱 此函数的功能是删除当前链表中的最小结点。

concatenate函数是把以pointer2以头的链表，接到pointer1链表的后面

纠正一处错误：12行应该是 if(tmp == NULL)


Question: 关于C语言指针与二维数组的理解，对否欢迎大家讨论

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式的值【比如printf("%p\n",...)】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=...】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

数组、指针、内存分配

数组就是指针,指针就是数组,没有区别

引用 4 楼 u010165006 的回复:[quote=引用 楼主 u010165006 的回复:] 比如一个数组int a[5]： a[i]==*(a+i)，a[0]==*a，两边取地址： &a[i]==a+i，&a[0]==a，a为数组首地址即第0个元素的地址，a[i]的类型是int，a的类型是int * 比如一个二维数组int a[5][10]： a[i]==*(a+i)，a[i][j]==*(*(a+i)+j)，a[i][0]==**(a+i)，a[0][0]==**a，两边取地址： &a[i]==a+i，&a[i][j]==*(a+i)+j，&&a[i][0]==a+i，&&a[0][0]==a，看第一项和第三项： a+i==&a[i]==&&a[i][0]，a[i][j]的类型是int，a[i]的类型是int *，a的类型是int **  二维数组首地址a，和第0行首地址a[0]，虽然二者值相等， 但是类型不一样，指针的类型就是对指向的数据的解释，所以二者是不同的。 a[i]的类型应该是 (int *)[10][/quote] a[i]的类型是int *，a的类型是int (*)[10]

引用 楼主 u010165006 的回复:比如一个数组int a[5]： a[i]==*(a+i)，a[0]==*a，两边取地址： &a[i]==a+i，&a[0]==a，a为数组首地址即第0个元素的地址，a[i]的类型是int，a的类型是int * 比如一个二维数组int a[5][10]： a[i]==*(a+i)，a[i][j]==*(*(a+i)+j)，a[i][0]==**(a+i)，a[0][0]==**a，两边取地址： &a[i]==a+i，&a[i][j]==*(a+i)+j，&&a[i][0]==a+i，&&a[0][0]==a，看第一项和第三项： a+i==&a[i]==&&a[i][0]，a[i][j]的类型是int，a[i]的类型是int *，a的类型是int **  二维数组首地址a，和第0行首地址a[0]，虽然二者值相等， 但是类型不一样，指针的类型就是对指向的数据的解释，所以二者是不同的。 a[i]的类型应该是 (int *)[10]

路过~~~

。。。楼主你数学学得一定很不错，各种等式变换


Question: foj1750 ，自己测了好几组数据都没问题，提交还是WA，求指导。。。。

引用 1 楼 user-1 的回复:node[1].parent=0;  题目里有说1一定是根么？确定根节点就是看哪个数字没在左右儿子中出现过，但是怎么确定其他点的父节点是谁呢？？

引用 1 楼 user-1 的回复:node[1].parent=0;  题目里有说1一定是根么？对哦，是没有，但是它节点的编号是不是一定是1-N啊？？

node[1].parent=0;  题目里有说1一定是根么？

引用 2 楼 fzu215 的回复:[quote=引用 1 楼 user-1 的回复:] node[1].parent=0;  题目里有说1一定是根么？对哦，是没有，但是它节点的编号是不是一定是1-N啊？？[/quote] 看题目里怎么说咯。没说就不能默认。


Question: ctrl+c中断程序时出现异常，搞不定了……

引用 5 楼 sai_johnny 的回复:[quote=引用 3 楼 taodm 的回复:] 楼主啊，换本合格的教材吧。 还让你用ctrl_c结束程序的垃圾书都可以直接扔了。 呃。。怎么说？  OJ题目里很多都是给出多种测试用例，但没有结束条件。 所以结束程序的话，不是就得ctrl+c么？  以前好像都是while(scanf(...) != EOF)这样来做。 然后这次需要一个字符一个字符的读入，就没想那么多，直接按照主楼的代码做的。 结果就发现这个异常了……[/quote]  引用 6 楼 zhaowech 的回复:ctrl+c对程序来说本来就是异常，在调试的时候VS会捕获这个异常，通知用户处理，单独运行exe应该不会报异常了 此外，用户可以自定义ctrlhandler，来处理这个异常，防止报错 哦哦。主要是以前没有注意到这种异常。所以发现后就觉得很奇怪~~~

引用 3 楼 taodm 的回复:楼主啊，换本合格的教材吧。 还让你用ctrl_c结束程序的垃圾书都可以直接扔了。 呃。。怎么说？  OJ题目里很多都是给出多种测试用例，但没有结束条件。 所以结束程序的话，不是就得ctrl+c么？  以前好像都是while(scanf(...) != EOF)这样来做。 然后这次需要一个字符一个字符的读入，就没想那么多，直接按照主楼的代码做的。 结果就发现这个异常了……

引用 1 楼 jiangsheng 的回复:这是默认的行为 可以用SetConsoleCtrlHandler自定义 哦哦。但是有时可以直接可以把程序结束掉，没有提示中断异常。 而且在刷OJ题时，有一题总是Runtime error，就是结束程序这里出问题了。 题目没给出结束条件，那不就只能ctrl+c来结束程序么？

这个在默认情况下都会抛出异常的，ctrl+C就是为了中断存在的，可以用楼上方法自定义下。

这是默认的行为 可以用SetConsoleCtrlHandler自定义


Question: 关于C语言指针的讨论！！！

地址相同，类型可不相同哦，你打印下下面p1、p2的地址就知道了。 int *p1=&a[0][0]; int (*p2)[10]=&a[0]; p1++; p2++; printf("%p\n",p1); printf("%p\n",p2); 标准可没说一个地址只有一个类型哦，就好比3D影像，同一个点，不同角度看都是不同的。

引用 11 楼 u010165006 的回复:比如一个数组int a[5]： a[i]==*(a+i)，a[0]==*a，两边取地址： &a[i]==a+i，&a[0]==a，a为数组首地址即第0个元素的地址，a[i]的类型是int，a的类型==int * 比如一个二维数组int a[5][10]： a[i]==*(a+i)，a[i][j]==*(*(a+i)+j)，a[i][0]==**(a+i)，a[0][0]==**a，两边取地址： &a[i]==a+i，&a[i][j]==*(a+i)+j，&&a[i][0]==a+i，&&a[0][0]==a，看第一项和第三项： a+i==&a[i]==&&a[i][0]，a[i][j]的类型是int，a[i]的类型是int *，a的类型是int **  那么a[0]的地址和a[0]所指向的元素地址不就是一样的吗，这就矛盾了。a+n也是一样，如果表示双指针的话，a所指向的元素a[0]地址和a[0][0]的地址不就相重了。 a[0]的地址==a，类型是int ** a[0]所指向的元素地址==a[0]，类型是int * 上面2个虽然值相等，但是类型不一样，指针的类型就是对指向的数据的解释，所以二者是不同的，并不矛盾。 a[i]的类型是int *，a的类型是int (*)[10]

还是不大懂啊

记住一句话就行：指针的类型只是告诉计算机如何去解释这块内存，起始地址一样 解释出来的东西不一样就行了。

a[0]+n     //代表第1行第n个元素的地址 &a[0]和&a[n]    //分别代表第1行和第n=1行的首地址 注意：这儿的首地址是一样的，但是类型已经不和a[0]和a[n]一样了。

一个二维数组实际上是一个一维数组的一维数组。 数组是连续排列的元素，二维数组实际上是连续排列的一维数组，更高维类推。  所以int a[2][3]实际上是一个有两个元素的一维数组，每个元素是有三个int的一维数组。 a[0]是a的0号元素，也就是一个有三个int的一维数组。 但是为什么a[0]能执行+n呢？因为“一个一维数组的数组名可以隐式转换为指向第一个元素的指针”！ 所以a[0]是一个有三个int的一维数组，也可以隐式转换为指向这个一维数组的第一个int的指针，而指针就可以+n了。 实际上，a[0]这种写法本身就是指针的写法，a[0]首先把a从二维数组名转换为指向一维数组的指针，然后偏移0得到这个一维数组。 你可以去看语言标准，[]按规定是指针的用法，a[3]==*(a+3)==3[a]。  至于a[0]和a[0]的第一个元素地址相同，有什么可奇怪的吗？ 把每个人坐的位置按序号排列，各小组坐的位置连续，那么你们小组的第一个人坐的位置序号，同时也是你们小组的位置序号，只不过第一个人坐的位置大小为1，而你们小组坐的位置大小为n。 个体和整体的关系而已。  int a[2][3]的a不能隐式转换成int** a; a可以隐式转换为一个指向int[3]类型元素的指针，而不能隐式转换为一个指向int*类型元素的指针。 数组是一种类型，指针有地址和类型两个属性，就这么简单。

要有这个概念  a == &a[0]; a[0] == &a[0][0];

形象理解为指针就是一个箭头，指向一块内存，内存中存放的时内容

你这么去理解吧，指针是一种类型，它包括它的名字和大小。两者不要混淆。

计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495


Question: 求分析代码错误

非法访问内存 只因为你这样第定义了 char *str="I am a student!"; str指向一个字符串常量 无法被修改 char str[]="I am a student!"; 这样就行了

char *str="I am a student!";这个字符串是常量，不能修改，可以改成：char str[] = "I am a student!";


Question: c语言

多敲些例子，用着用着就懂了

这三种循环可以相互转换的，至于用哪个，主要看你对于那个比较熟悉，没有很大的区别。

你可以专心用一个 等你把这一个用熟了，你会发现其他两个你根本不需要去学，拿过来就会用 本质都是一样的，代码编译成可执行文件之后甚至有可能一模一样，就看你习惯用哪个

引用 楼主 u012331408 的回复:for, while,do while 如何区分？如何运用更何适？ 运用上都一样，只不过根据具体情况而定有更合适的

跟上节奏。 避免死循环！。。没别的

熟能生巧！。。没别的

引用 5 楼 zhao4zhong1 的回复:不要使用 while (条件) 更不要使用 while (组合条件) 要使用 while (1) {  if (条件1) break;  //...  if (条件2) continue;  //...  if (条件3) return;  //... } 因为前两种写法在语言表达意思的层面上有二义性，只有第三种才忠实反映了程序流的实际情况。 典型如： 下面两段的语义都是当文件未结束时读字符 whlie (!feof(f)) {  a=fgetc(f);  //...  b=fgetc(f);//可能此时已经feof了！  //... } 而这样写就没有问题： whlie (1) {  a=fgetc(f);  if (feof(f)) break;  //...  b=fgetc(f);  if (feof(f)) break;  //... } 类似的例子还可以举很多。 do while也类似。 赵老板 每次都一大堆文字 不累么


Question: linux程序设计

引用 4 楼 wsx199397 的回复:[quote=引用 2 楼 Adol1111 的回复:] 判断peek_character是否被修改过，如果有则直接返回的意思 因为peek_character的初始值是-1所以第一次调用kbhit函数时是不会执行这两句的。然后如果键入了一个值peek_character被修改了，但是接下来肯定要执行readch函数因为被修改了所以肯定不会等于-1，然后执行 if(peek_character!=-1)   {     ch=peek_character;     peek_character=-1;     return ch;   } 就把peek_character重置了，所以每次运行到kbhit时肯定不会这些那两条语句啊。[/quote] 多线程啊，在这条线程还没有重置peek_character的情况下，另一条线程进入了这个函数那么就可以执行啦。

引用 2 楼 Adol1111 的回复:判断peek_character是否被修改过，如果有则直接返回的意思 因为peek_character的初始值是-1所以第一次调用kbhit函数时是不会执行这两句的。然后如果键入了一个值peek_character被修改了，但是接下来肯定要执行readch函数因为被修改了所以肯定不会等于-1，然后执行 if(peek_character!=-1)   {     ch=peek_character;     peek_character=-1;     return ch;   } 就把peek_character重置了，所以每次运行到kbhit时肯定不会这些那两条语句啊。

引用 1 楼 user-2 的回复:不起作用，注释掉了  这个是为了引起注意，我故意注释掉的好哇。。。。

不起作用，注释掉了


Question: 局部指针变量的疑问

堆是堆， 栈是栈， 什么叫结构都在堆栈上啊！  局部变量的话，不是自己分配的应该就是在栈空间了啊！  生命周期就在此变量定义的的{}内呗！ 运行到}系统就自动释放掉

你定义的指针变量（只要没有自己申请内存且没有声明为全局或静态变量），那么都在栈上。 而且记住一点，无论是什么类型的指针变量，它都只占4个字节（不一定，跟平台有关），里面存放地址，所以它并不存在你所说的定义结构体指针变量时，也定义结构体内的成员变量的情况。所以用的时候，你要把指针指向一个已经存在的相同结构体变量的地址。

使用指针要记住一点，“他引用了一个不在当前位置的对象” 对象的位置无关紧要，也许他在.dll文件中。  如果你想在栈中创建结构，那就把结构定义在函数内好了。  结构是不允许在函数间直接传递的。

指针变量，你可以理解为是一个普通变量，占四个字节。所以在栈上存放的。它与普通变量的区别就在该变量里存放的不是普通值，而是地址值，是内存中某个地址的值。

你的指针在局部定义的，那就在栈上，它指向的结构在哪里定义的？

引用 楼主 dragonballlike 的回复:函数中定义一个局部结构指针变量，在编译运行的时候，整个结构都在堆栈上，还是只有结构指针在栈上？ 如果是后者，那结构存储在哪？他的生命期是什么？  指针还是在栈上，指针指向的内容在堆区 仔细区分一下不同变量存储的不同区域 常量区 静态区 栈区 堆区

这个指针如果不是静态的，可必定实在栈上，指向的数据可以在堆上也可以在栈上


Question: 一个关于结构体指针交换的问题。

引用 5 楼 user-3 的回复:你这是个排序啊，你排序算法有问题阿好的。。醒悟了！ 哈哈 去研究一下~

排序错了！！！

引用 4 楼 qq695181966 的回复:[quote=引用 3 楼 user-3 的回复:] 不是，错了，应该是 *t=*p;     //把p所指向的东西给t *p=*(p+1);  //p+1所指向的东西给p *(p+1)=*t;  //t所指向的东西给p+1我刚才就是按你这么写的 但是输出的结果是不对的~~[/quote] 那是你排序算法本身有问题啊。

指针内容交换，不是指针地址交换。 看楼上的代码就行了。

你这是个排序啊，你排序算法有问题阿

引用 3 楼 user-3 的回复:不是，错了，应该是 *t=*p;     //把p所指向的东西给t *p=*(p+1);  //p+1所指向的东西给p *(p+1)=*t;  //t所指向的东西给p+1我刚才就是按你这么写的 但是输出的结果是不对的~~

你这交换的只是指针的值，指针所指向的内容并没有变， 应该改成 t=p; *(p+1)=*p; *p=*t;

我是应该定义一个结构体指针，然后在if{}交换语句中将其作为中间变量来交换地址对吗？


Question: Typedef struct list node这是什么意思

引用 2 楼 u011779875 的回复:node 相当于 struct list的替换 link 相当于 node* 双重替换 就是 struct list * 引用 1 楼 u011779875 的回复:typedef struct list node;  typedef node *link;  void main() {     link ptr,head;  } typedef 就是把类型从命名  node p; 相当于 struct list p;  typdef node * link; 相当于 struct list * p;   懂了，谢谢