简体   繁体   English

C 中的全局变量丢失数据?

[英]Global variable losing data in C?

I am trying to create a array of array of string where each row (if considered matrix) should have 3 strings of any length and a maximum of 10 rows我正在尝试创建一个字符串数组,其中每行(如果考虑矩阵)应该有 3 个任意长度的字符串,最多 10 行

The data Structure is correct but I am very much surprised with the output I get in the global variable.数据结构是正确的,但我对全局变量中的 output 感到非常惊讶。 So the matrix would act as the database to the program and hence kept in global space所以矩阵将作为程序的数据库,因此保存在全局空间中

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

// Maximum buffer size needed
#define MAX_NUM_ITEMS 10
#define MAX_ITEM_PER_ROW 3
static char *array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW];

#define ITOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 1)
char *itoa_base(char *, int , int);
#define TO_BASE(x,b) itoa_base((char [ITOA_BASE_N]){0} , (x), (b))


char *itoa_base(char *s, int x, int base) {
  s += ITOA_BASE_N - 1;
  *s = '\0';
  if (base >= 2 && base <= 36) {
    int x0 = x;
    do {
      *(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[abs(x % base)];
      x /= base;
    } while (x);
    if (x0 < 0) {
      *(--s) = '-';
    }
  }
  return s;
}

int main(void)
{   
    
    int count = 0;
    for (int i = 0; i < MAX_NUM_ITEMS; i++){
        for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
            ++count;
            array[i][j] = TO_BASE(count, 16);
        }
    }
    
    for (int i = 0; i < MAX_NUM_ITEMS; i++){
        for (int j = 0; j < MAX_ITEM_PER_ROW; j++ ){
            printf("%s ",array[i][j]);
        }
        printf("\n");
    }
    return 0;
}

From my logic I should see 1 2 3 4 5 6 7 8 9 and so on and not EEE根据我的逻辑,我应该看到 1 2 3 4 5 6 7 8 9 等等,而不是 EEE

can't understand why that is happening无法理解为什么会这样

First, this:首先,这个:

(char [ITOA_BASE_N]){0}

Does not get you a new instance of a character array, unlike say golang.不像 golang 那样,不会给你一个字符数组的新实例。 So, every time you call itoa(), you are calling it with the same character array.因此,每次调用 itoa() 时,都会使用相同的字符数组调用它。 Somewhat worse, the character array is occupying a reclaimable stack address [ its scope is only that inner loop ], so it can be over written with random stuff shortly after.更糟糕的是,字符数组占用了一个可回收的堆栈地址[它的 scope 只是那个内部循环],所以不久之后它可以被随机的东西覆盖。 It is remarkably consistent though;但它非常一致。 I will give it that.我会给它。

Changing the invocation to:将调用更改为:

array[i][j] = strdup(TO_BASE(count, 16));

and adding a #include at the top produces the output you wanted.并在顶部添加 #include 会产生您想要的 output 。

If dynamic allocation is not permissible in your application, you will have to use a static allocation scheme, which you could make a bounded version of strdup like:如果您的应用程序中不允许动态分配,您将不得不使用 static 分配方案,您可以创建一个有界版本的 strdup,例如:

char *strnew(char *s) {
  static char strspace[ITOA_BASE_N * MAX_NUM_ITEMS * MAX_ITEM_PER_ROW ];
  static char *strnext = strspace;
  if (strlen(s) + strspace >= &strspace[sizeof strspace]) {
      s = "<error: out of space>"; /* something more clever is possible */
  } else {
      strcpy(strnext, s);
      s = strnext;
      strnext += strlen(strnext)+1;
  }
  return s;
}

which you could substitute for strdup.你可以用它来代替 strdup。 If you do the next person down the line a favour and use a more descriptive notion like MAX_STRING_SPACE which is based on the calculation;如果您帮下一个人一个忙,并使用基于计算的 MAX_STRING_SPACE 等更具描述性的概念; and rather than insert a "bad value", cause some sort of exception, I am sure they would appreciate it.而不是插入“坏值”,导致某种异常,我相信他们会很感激。

The problem is here:问题在这里:

itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
          ^^^^^^^^^^^^^^^^^^^^^^^

you are allocating a temp array (on the stack) which is only valid up to the end of the containing expression statement.您正在分配一个临时数组(在堆栈上),该数组仅在包含表达式语句的末尾有效。 So when the time comes to print them, the pointers you've stored in the matrix are dangling.因此,当需要打印它们时,您存储在矩阵中的指针是悬空的。 What the compiler ends up doing is reusing the same memory for every call, so the strings end up overwriting.编译器最终会为每次调用重用相同的 memory,因此字符串最终会被覆盖。

You could instead use a static matrix of arrays rather than pointers:您可以改为使用 arrays 的 static 矩阵而不是指针:

static char array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW][ITOA_BASE_N];

then your call in the first loop becomes那么你在第一个循环中的调用变为

itoa_base(array[i][j], count, 16);

you'll also need to "fix" itoa_base so it puts the result in the front of the array rather than the back.您还需要“修复” itoa_base以便将结果放在数组的前面而不是后面。 Obvious way is with a recursive loop like:明显的方法是使用递归循环,例如:

char *itoa_base(char *s, int x, int base) {
  if (base >= 2 && base <= 36) {
    if (x < 0) {
      *s++ = '-';
      x = -x; }
    if (x >= base)
      s = itoa_base(s, x/base, base);
    *s++ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x % base];
  }
  *s = '\0';
  return s;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM