1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace 数组的排序练习 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 string[] names = { "梅西", "卡卡", "郑大世" }; 13 string s; 14 //在for循环语句不是个s赋值了,怎么还是报错“局部变量S未赋值” 15 for (int i = 0; i < names.Length-2; ) 16 { 17 s=names[i]+"|"; 18 Console.Write(s); 19 i++; 20 } 21 s=s+names[names.Length-1]; 22 Console.WriteLine(s); 23 24 Console.ReadKey(); 25 } 26 } 27 }
程序报错:使用了未赋值的局部变量“s”(即代码中的红色s),可是我不是在for语句中,已经赋值初始化了吗?
希望各位老师们,指导学生,指点迷津
前面很多人都已经正确指出了你的错误和解决方案,但是我看了你的评论,似乎对for循环的理解有误。你认为“编译器应当知道names.Length - 2 > 0",所以“编译器应当知道for循环是肯定执行的”,所以“编译器应当知道s一定会被赋值”。实际上for循环的语法是这样的:
for (初始化语句; 结束条件; 每次循环完成时执行的语句) { 循环主体 }
试想一个for语句可能是这样的:
for (int i = 0; Test(i); Go(i)) { //循环主体 }
其中Test(i)是一个非常复杂和耗时的方法。在这种情况下,编译器很难尝试去“检测Test(i)", 事实上这样做的意义也不大。
总结一下就是:for循环的结束条件表达式,编译器”总是认为“它是一个“运行时才能得到的值”,即使“你提供了一个总是为真的表达式”。这方面跟if-else和switch不同。编译器用很小的代价就可以知道if-else/switch分支是否总是会给s赋值:
string s; if (Test(1)) //Test是某个返回bool的函数 { s = "1"; } else { s = "2"; } //在此之后编译器能够很容易意识到s被赋值了,无论Test方法的实现是怎样的 //switch同理
牛哥,我看了你的表达,我想问下,你是说:编译器是负责语法逻辑检测的,但是由于for循环语句【 for (int i = 0; i < names.Length-2; )】,编译器只对for循环语句进行语法检测,且对于这些循环体的变量赋值问题,一概默认为条件不成立(即使逻辑上是成立的,但是编译器为了提高效率,不进行多次循环逻辑判断,全部默认不成立),所以【s=names[i]+"|"】,虽然有赋值语句,但是程序认为for循环成立,对变量S的赋值初始化,根本没有执行,到了这句【s=s+names[names.Length-1]】,造成编译器认为我们使用了未初始化的变量s,进行赋值运算。
我的理解有错吗?希望指点,牛哥
@黑夜猫头鹰: “一概默认为条件不成立”,更准确的说是“编译器认为有可能不成立”,即“s有可能未被赋值”。
你的代码不能通过 VS 的编译,起码要赋空值。
我知道将string s="";程序可以编译通过,但是我在for语句赋值也行啊,怎么就不可以呢?是我在知识点上有误区吗?我想知道为什么
我大概说下我的理解啊,主要的原因是 当你 不初始化 s的时候,s没有分配内存空间,然后s就不能作为一个值去使用
s=s+"zhi"; 或者 s+="zhi";都不可以,
而你这里的问题是 在程序买没有执行之前,是不能确定for循环里的内的东西用一定能执行,比如names.length==0的话
所以,声明变量时候一定要初始化,这是程序员的基础知识了,即使 string s = null;也可以。
其实我也有这样想法:【在程序买没有执行之前,是不能确定for循环里的内的东西用一定能执行】
但是后来想想,程序在编译时是从上到下顺序编译的,
当编译器读取到【s=s+names[names.Length-1]】这句时,早就通过了for循环,知道肯定能通过for语句给变量s赋值,在需要使用变量s时,都对变量S进行赋值初始化了。
@黑夜猫头鹰:
1、我也认为是编译器不会识别for内部赋值语句,就像if……else……中赋值一样。
2、编译器也并不一定从上到下,会有编译优化
3、编译器编译的时候也不会去执行你的代码,只是进行类型安全检查,访问权限之类的检查和其他。
你至少得初始化啊,都没有分配内存空间,怎么去对变量进行操作
这一句,不是【 s=names[i]+"|"】不是赋值初始化了吗?
@黑夜猫头鹰: 变量定义的时候就要分配内存的
@飘雪无痕007: 我只听过”变量在使用前要赋值初始化“,没有这”定义是就要分配内存地址“???
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace ConsoleApplication4 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 string a; 13 string b = Console.ReadLine(); 14 a = b; 15 Console.WriteLine(a); 16 } 17 } 18 }
照你的说法,呢么怎么变量a又可以运行呢??
for循环里面的语句会不会执行编译器是不知道的,这个s是一个运行时变量,而编译器检查的时候并不会认为你的s有值,因此是不能做右值被别的表达式使用的。
因此在遇到这种不一定会执行的语句的时候编译器其实是认不出s的值的。所以要在声明的时候初始化,即
string s = string.Empty;
这样是最好的方法。
其实我也有这样想法:【在程序买没有执行之前,是不能确定for循环里的内的东西用一定能执行】
但是后来想想,程序在编译时是从上到下顺序编译的,
当编译器读取到【s=s+names[names.Length-1]】这句时,早就通过了for循环,知道肯定能通过for语句给变量s赋值,在需要使用变量s时,都对变量S进行赋值初始化了。
@黑夜猫头鹰: 都说了,编译器是无法判断你的for语句能否跑完的。
@飞鸟_Asuka: 我想问下,我这里有个概念不是很懂
[这个s是一个运行时变量,而编译器检查的时候并不会认为你的s有值,因此是不能做右值被别的表达式使用的],右值是什么?
1 编译器检测时,程序不是运行了吗?
2“s是运行时变量”,请问有“非运行时变量”吗?
以上的问题导致我对这句【这种不一定会执行的语句的时候编译器其实是认不出s的值的】不解?
以为我是观点是{当编译器读取到【s=s+names[names.Length-1]】这句时,早就通过了for循环,知道肯定能通过for语句给变量s赋值}
希望你能,指点我,感谢你
@黑夜猫头鹰: 编译器不会运行你的程序,它只会做一些语法上的检查。但是你这里把s用于赋给一个变量,而编译器检测到你的s只有声明没有值,因此认为这个语句不符合语法于是报错。编译器并不会跑你的程序来确定for循环会不会运行
定义成静态变量,每次跳出循环s为空的缘故
string s ;程序默认不给分配内存地址 所以会报错
计算机怎么知道一定会走for循环呢? 你如何保证for循环一定会执行呢?
string s; 修改为
string s="";
其实我也有这样想法:【在程序买没有执行之前,是不能确定for循环里的内的东西用一定能执行】
但是后来想想,程序在编译时是从上到下顺序编译的,
当编译器读取到【s=s+names[names.Length-1]】这句时,早就通过了for循环,因为【string[] names = { "梅西", "卡卡", "郑大世" }】,则编译器通过判断,肯定能通过for语句给变量s赋值,在需要使用变量s时,都对变量S进行赋值初始化了