void main()
{
int x[]={85,75,27,40,65,98,74,89,12,5,46,97,13,69,52,26,19,92};
int *p;
int i=0,j=0;
for(i=0;x[i]!=0;i++)
{
j+=1;
printf("%d\t",x[i]);
}
printf("\n");
printf("%d",j);
}
不知道为什么记数结果是21,,搞不明白
补充一点:从做法上看,你好像认为数组之外自然会以0结尾,这种想法完全不正确。事实上,在经典的C语言进程内存区组织结构中,数组之后紧跟的应当是其他栈内容。栈上的内容一般与函数调用的保存现场、跳转逻辑和局部变量有关,这个特性使得栈溢出攻击成为可能。如果数组后紧随的是跳转逻辑用到的地址,就能发动控制流劫持(control flow hijacking)。如果数组后紧随的是局部变量,就可能被利用来窃取敏感数据。因此,试图利用局部数组上越界的部分,实际上是极度危险的操作,任何现代公司都几乎不可能允许技术人员这样做。
顺便一提,一个常见的误解是“未分配的空间上值默认为0”,这个想法也是完全错误的。未分配的空间上可以是任何值。对于malloc获取的空间,也不会有初始化。
之前说“只有字面值常量字符串初始化的char数组才会自然以0结尾”不够严谨,后面的回复已经做了纠正哈。
你的计数逻辑是“当前值为0就认为有效值结束,计数终止”,但你的数组实际上没有以0结尾,这当然是错误的。
只有一种数组会自然以0结尾:以const char*字面值常量字符串初始化的、以char为基本元素的数组,而且分配数组时长度还得足够容纳下新的0(不够的话编译器会报warning或error。举例而言,这样的代码是错误的:const char p[5] = "hello";,因为5字节空间仅仅足以容纳5个字符,而字符串以0结尾,需要至少6字节)。其他类型数组都不会自然以0结尾。
再补充一点:事实上,C语言标准也没有规定局部数组一定要初始化;事实上,多数编译器实现中,函数内的局部数组和变量是不会被初始化的。如果合理地显式指定数组初始化(像你现在代码里这样,利用大括号语法来初始化局部数组),初始化表没列出的值(如果初始化表长度小于数组分配长度)会被置0,所以如果你写成int x[100] = {/*这里是用来初始化数组的值*/};(与你代码的关键区别在于,显式指定了数组长度,因此多出来的部分会被自动置0)的话,倒是可以得出正确结果。但如果你写成int x[100];(没有大括号初始化)而且仍作为局部数组,由于没有显式初始化的局部数组不会被自动初始化,你仍然有很大可能得到错误结果。
明白了,感谢大佬!
列表中并没有值为0的数据,而你让循环在值为0时停止,显然不对。尽管我没学过C语言,但C++、Python、JavaScript都没有“索引超出部分值为0”这一说,Python中更是不让开发者超出索引,会报错。但说如何修改,是真不好说,毕竟我也没学过C语言。但凭着我对C++的认识,我觉得,既然是新手程序,思想绝没有错,应该是刚学for循环吧,可以把侧重点改一下,例如用for循环遍历列表。p指针没有用到,说不定你正在学习指针与数组,测试阶段出了小问题。如果你的主要目的不是获取列表的长度,你完全可以通过其他函数或网上教学的方法来获取列表长度,没必要因为一点小问题而斟酌,毕竟你的目标不是这个。