【问题标题】:printf won't print double type array valuesprintf 不会打印双精度类型的数组值
【发布时间】:2019-02-09 01:15:05
【问题描述】:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define N 8

typedef struct Array {
    double element[N][N];
} Array;

void PrintArray(Array a) {
    int i;
    int j;
    for (i = 0; i < 64; i++) {
        for (j = 0; j < 64; j++) {
             printf("%d ", a.element);
        }
    } // for
} // PrintArray

int main(int argc, const char *argv[]) {
    Array M = {
        { 174, 143, 143, 143, 143, 143, 143, 156,
          192, 200, 156, 174, 174, 174, 156, 110,
          254, 198, 174, 174, 200, 174, 143, 143,
          239, 200, 156, 200, 200, 166, 143, 143,
          200, 174, 156, 167, 166, 149, 156, 156,
          128, 156, 143, 156, 174, 200, 198, 174,
          143, 105, 110, 149, 156, 156, 200, 166,
          110, 156, 143, 143, 143, 156, 174, 156 }
    };

    // need to implement PrintArray
    PrintArray(M);

    return EXIT_SUCCESS;
}

【问题讨论】:

  • 请参阅minimal reproducible example。您缺少清晰的问题描述,Q50 未使用。
  • 总是在启用警告的情况下编译,并且不要接受代码,直到它在没有警告的情况下干净地编译。要启用警告,请将 -Wall -Wextra 添加到您的 gccclang 编译字符串中。 (添加-pedantic 以获得其他几个警告)。对于clang,您可以改用-Weverything。对于 VS(windoze 上的cl.exe),添加/W3(或使用/Wall,但您会收到很多无关的非代码相关警告)。阅读并理解每个警告。他们将识别任何问题,以及它们发生的确切线路。通过聆听编译器告诉您的内容,您可以学到很多东西。

标签: c arrays struct printf double


【解决方案1】:

注意:

  1. 您应该使用以下说明符来打印您的数组,而不是 "%d""%i"
    • %e (%E) 浮点或双指数格式
    • %f浮点数或双符号十进制
    • %g (%G) 根据需要浮动或双重使用 %f%e
  2. 您的二维数组具有8x8 维度,因此请在循环中使用N 常量。
  3. 还可以使用[i][j] 选择要打印的数组元素。

试试这个:

void PrintArray(Array a){
      int i;
      int j; 
        for (i=0; i<N; i++)
        {
            for (j=0; j<N; j++)
            {
                printf("%g ", a.element[i][j]);
            }
            printf("\n");
        }
}

输出如下:

174 143 143 143 143 143 143 156
192 200 156 174 174 174 156 110
254 198 174 174 200 174 143 143
239 200 156 200 200 166 143 143
200 174 156 167 166 149 156 156
128 156 143 156 174 200 198 174
143 105 110 149 156 156 200 166
110 156 143 143 143 156 174 156

使用"%d" 而不是"%g" 来表示double 数字的输出具有未定义的行为,因此它可能会打印0 或实际值:

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

【讨论】:

  • 谢谢。我觉得我已经完成了过去几天我能找到的每一次迭代。我不知道 %g,也没有在我的书中看到它。我确实尝试了 %f 和 %1f,但它们没有循环,但我认为它们也是用于打印双打,我发现这是不正确的。我现在也将尝试实现其他功能。我可能会在几天后回来,我希望不会,但这对我有很大帮助。
  • @JackD 欢迎您。你可以接受我的回答,如果可以帮助你
  • @JackD %f%g%e 都可以用于打印双打(以不同的格式)。 %1f 表示 %f 的最小字段宽度为 1,这是多余的(%f 将始终产生至少一个字符的输出)。 printf 中的 %lf 要么等同于 %f (C99+) 要么具有未定义的行为 (C90),所以它几乎没用。
  • @melpomene 谢谢,我根据你的观点更正了我的答案
  • 请注意,将double 传递给printf %d 具有未定义的行为,因此不能保证您会看到0
【解决方案2】:

你有很多小东西,每一个都足以在你的程序中调用未定义的行为。对于初学者,您可以正确声明常量#define N 8,然后在遍历您的array-within-a-struct 以打印时忽略该常量,例如

#define N 8
...
void PrintArray(Array a){
...
    for (i=0; i<64; i++){
        for (j=0; j<64; j++){

您只有一个 8x8 双精度数组。然后,当您尝试迭代 4096 次而不是 64 次时-您远远超出了数组范围(除非您的 a.element 实际上并没有访问数组的任何元素-因此您完全愚蠢地避免了未定义的行为-运气...)

但是,在传递指向双精度数组的指针时,您确实使用 %dformat-specifier 调用 Undefined Behavior(传递格式不正确的类型-说明符调用未定义的行为)。相反,在这里,为了避免打印 double 值(除非存在)的小数位,请使用 %g format-specifier 而不是 %d(用于 integer 仅转换,甚至可能与您尝试打印的字节数不同)。

使用您定义的常量(并在修复初始化和格式说明符之后),您可以这样做:

void print_array (Array a)
{
    int i, j;

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) 
            printf (" %3g ", a.element[i][j]);  /* note the use of i & j */
        putchar ('\n');
    }
}

(注意:虽然不是错误,但 C 的标准编码风格避免使用 camelCaseMixedCase 变量名,而支持所有小写 同时保留 大写 名称以用于宏和常量。)

此外,在 C 中,您需要将 指针 传递给结构,而不是结构本身。这允许在每个函数调用上仅传递 sizeof (a_pointer) 的信息,而不是传递整个结构本身的副本。所以你的print_array 函数可以更恰当地写成:

void print_array (Array *a)
{
    int i, j;

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) 
            printf (" %3g ", a->element[i][j]);  /* note the use of -> */
        putchar ('\n');
    }
}

注意:要在main() 中传递结构的地址,您可以将print_array 称为print_array (&amp;M);

您对Q50M 的初始化都是错误的。你使用:

Array Q50 = {{18, 11, 10, 18, 26, 40, 51, 61,
    12, 12, 14, 19, 26, 58, 60, 55,
    14, 13, 18, 26, 40, 57, 69, 56,
    14, 17, 22, 29, 51, 87, 80, 62,
    18, 22, 37, 56, 68,109,103, 77,
    26, 35, 55, 64, 81,104,113, 92,
    49, 64, 78, 87,103,121,120,101,
    72, 92, 95, 98,112,100,103, 99}
};

(你的编译器应该对你发出警告——你需要阅读、理解和修复——并且在编译干净之前不要接受代码——没有警告)

struct foo 的基本初始化是 struct foo = { .... },其中 { ... } 的内容可以使用 named-initializer 或为结构的部分或所有成员提供值。在这里,您的struct 有一个成员或输入double [N][N]

要初始化一个二维数组,初始化是type array[N][N] = {{0 ... N-1}, {1 ... N-1}, ... {N-1 ... N-1}}; 所以你的array-within-a-struct 需要3个大括号,例如Array M = {{{0...N-1}, {1...N-1}, {...}}}.

将结构的初始化和它包含的二维数组都放入将导致初始化类似于:

    Array M = {{{174, 143, 143, 143, 143, 143, 143, 156},
                {192, 200, 156, 174, 174, 174, 156, 110},
                {254, 198, 174, 174, 200, 174, 143, 143},
                {239, 200, 156, 200, 200, 166, 143, 143},
                {200, 174, 156, 167, 166, 149, 156, 156},
                {128, 156, 143, 156, 174, 200, 198, 174},
                {143, 105, 110, 149, 156, 156, 200, 166},
                {110, 156, 143, 143, 143, 156, 174, 156}}};

总而言之,您可以执行类似以下的操作:

#include <stdio.h>

#define N 8

typedef struct Array {
    double element[N][N];
} Array;


void print_array (Array a)
{
    int i, j;

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) 
            printf (" %3g ", a.element[i][j]);
        putchar ('\n');
    }
}


Array Q50  =  {{{18, 11, 10, 18, 26, 40, 51, 61},
                {12, 12, 14, 19, 26, 58, 60, 55},
                {14, 13, 18, 26, 40, 57, 69, 56},
                {14, 17, 22, 29, 51, 87, 80, 62},
                {18, 22, 37, 56, 68,109,103, 77},
                {26, 35, 55, 64, 81,104,113, 92},
                {49, 64, 78, 87,103,121,120,101},
                {72, 92, 95, 98,112,100,103, 99}}};

int main (void)
{
    Array M = {{{174, 143, 143, 143, 143, 143, 143, 156},
                {192, 200, 156, 174, 174, 174, 156, 110},
                {254, 198, 174, 174, 200, 174, 143, 143},
                {239, 200, 156, 200, 200, 166, 143, 143},
                {200, 174, 156, 167, 166, 149, 156, 156},
                {128, 156, 143, 156, 174, 200, 198, 174},
                {143, 105, 110, 149, 156, 156, 200, 166},
                {110, 156, 143, 143, 143, 156, 174, 156}}};

    puts ("\nprinting M\n");
    print_array (M);

    puts ("\nprinting Q50\n");
    print_array (Q50);

    return 0;
}

使用/输出示例

$ ./bin/structarrayq50

printing M

 174  143  143  143  143  143  143  156
 192  200  156  174  174  174  156  110
 254  198  174  174  200  174  143  143
 239  200  156  200  200  166  143  143
 200  174  156  167  166  149  156  156
 128  156  143  156  174  200  198  174
 143  105  110  149  156  156  200  166
 110  156  143  143  143  156  174  156

printing Q50

  18   11   10   18   26   40   51   61
  12   12   14   19   26   58   60   55
  14   13   18   26   40   57   69   56
  14   17   22   29   51   87   80   62
  18   22   37   56   68  109  103   77
  26   35   55   64   81  104  113   92
  49   64   78   87  103  121  120  101
  72   92   95   98  112  100  103   99

检查一下,并阅读我关于启用编译器警告的评论,如果您还有其他问题,请告诉我。

【讨论】:

  • 相当广泛的答案!我要补充一点,在 C 中将指针传递给诸如 Array 之类的结构是惯用的,而不是按值传递它们,而是倾向于 void print_array(const Array *a) 的原型。
  • “如果您还有其他问题,请告诉我。”.. 问:我如何才能了解您所知道的内容,具有相似的知识深度 :-) + 1.
  • 学习 C 不是你随便做的事,它更像是一段旅程。学习它的方法,就是好奇,总是问“为什么代码是这样写的,或者为什么用puts而不是printf?”等等。一次找到一个答案。 (有很多把你的头撞到中间的墙上)。它真的可以归结为你吃鲸鱼的方式——一次咬一口:)
  • @DavidC.Rankin:就像我说的,我是粉丝 :-)
  • @DavidC.Rankin:我喜欢鲸鱼的比喻!当然,在 C 中,一次学习一个字节,有时甚至一次只学习一个位。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-22
相关资源
最近更新 更多