Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 语法困难,出乎意料的输出_C_Grammar - Fatal编程技术网

C 语法困难,出乎意料的输出

C 语法困难,出乎意料的输出,c,grammar,C,Grammar,你能告诉我为什么运行这两个代码我有不同的输出吗 void UART_OutString(unsigned char buffer[]){ int i; while(buffer[i]){ UART_OutChar(buffer[i]); i++; } } 及 尊敬的Genadi,不管它值多少钱,我都会把它实现为 void UART_OutChar(unsigned char c); void UART_OutString(uns

你能告诉我为什么运行这两个代码我有不同的输出吗

    void UART_OutString(unsigned char buffer[]){
    int i;
    while(buffer[i]){
        UART_OutChar(buffer[i]);
        i++;
    }
}


尊敬的Genadi,不管它值多少钱,我都会把它实现为

void UART_OutChar(unsigned char c);

void UART_OutString(unsigned char buffer[]){
    for(unsigned char *p = buffer; *p; p++) {
        UART_OutChar(*p);
    }
}

完全避免使用单独的计数器变量。

初始化局部变量总是一个好主意,尤其是在C语言中,您应该假设没有为您做任何事情(因为通常情况就是这样)。受监管的语言不允许您这样做是有原因的

我相信读取未赋值变量会导致未指定的行为(实际上C不知道那里没有任何东西,只会抓住任何东西),这意味着它是完全不可预测的

这也可能会导致各种问题,因为您随后会使用它对数组进行索引,而C不会阻止您将数组索引到超出范围的位置,因此如果C恰好获取的随机
i
值大于数组的大小,那么您将在
缓冲区[i]
返回的内容中遇到未定义的行为。这可能是特别令人讨厌的,因为它可能会导致任何类型的内存读取/分段错误,从而导致程序崩溃,这完全取决于它决定读取的内容

因此unassigned
i
=随机行为,然后使用该
i
值对数组进行索引,可以获得更多的随机行为

我相信这是一个坏主意的所有原因。在C语言中,特别重要的是要注意这样的事情,因为它通常允许您编译和运行代码


初始化i和使用@AKX答案中的解决方案都是很好的解决方案,尽管我认为这更能回答您的问题,即为什么它们返回的结果不同。真正的答案是第一种方法完全随机返回在第一种情况下,您没有初始化
i
变量,因此这是一个无趣的打字错误,您的编译器应该提醒您


也就是说,我们可以应用for循环,并以尽可能可读的方式重写整个代码,因为它的性质使得很难忘记初始化循环迭代器:

void UART_OutString(const char* buf[]){
  for(int i=0; buf[i]!='\0'; i++){
     UART_OutChar(buffer[i]);
  }
}
事实证明,最具可读性的方式往往也是最快的方式


(然而,
int
在某些低端系统上可能效率低下,因此,如果您可以只使用长度为255或更小的字符串,
uint8_t i
将是一个更好的选择。嵌入式系统永远不应该使用
int
并且总是使用
stdint.h
类型。)在第一个代码中未初始化,首先…默认情况下不是等于零吗?在调试器中,我还看到“int I”的值=0x0是否在编译器中启用警告?(默认情况下,局部变量不会初始化)。@Gendozz您很幸运,它恰好在该点为零,但不,它在默认情况下不会初始化。在第一部分中,您不会在0处初始化i。请您解释为什么不保留计数器更好?@Gendozz使用计数器时,您需要在每次迭代中递增计数器。每次还需要将计数器添加到指针值。如果移除计数器,只需增加指针值。这并不一定更好。UART意味着这是一个嵌入式系统。让我们假设一个8位微控制器,具有8位索引寄存器,但具有16位地址总线。然后,此代码将强制执行16位算术,而不是8位,从而导致代码速度慢得多。在大多数系统上,读取未初始化的局部变量(未获取其地址)会导致未指定的行为。但是,由于越界访问,使用数组索引这样的变量几乎肯定是未定义的行为。感谢Lundin,我将编辑我的答案,以便在每个实例中使用正确的术语。虽然如果有技术上的差异,我希望您能解释一下?关于未初始化变量的具体情况,请参阅。关于未定义的行为与未指定的行为,请参阅。TL;DR is:未定义的行为意味着任何疯狂的事情都可能发生,比如代码被优化。Wheras未指定的行为是未记录的,编译器/系统特定的行为,如果被依赖,可能会产生意外的结果,但不会像未定义的行为那样导致编译器完全崩溃。干杯,哦,我很少依赖我的C代码不会完全崩溃,哈哈
void UART_OutString(const char* buf[]){
  for(int i=0; buf[i]!='\0'; i++){
     UART_OutChar(buffer[i]);
  }
}