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

全局变量在C中丢失数据?,c,C,我试图创建一个字符串数组,其中每行(如果考虑矩阵)应该有3个任意长度的字符串,最多10行 数据结构是正确的,但我对全局变量中的输出感到非常惊讶。因此,矩阵将充当程序的数据库,因此保存在全局空间中 #include <stdio.h> #include <stdlib.h> #include <limits.h> // Maximum buffer size needed #define MAX_NUM_ITEMS 10 #define MAX_ITEM_PE

我试图创建一个字符串数组,其中每行(如果考虑矩阵)应该有3个任意长度的字符串,最多10行

数据结构是正确的,但我对全局变量中的输出感到非常惊讶。因此,矩阵将充当程序的数据库,因此保存在全局空间中

#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;
}
#包括
#包括
#包括
//所需的最大缓冲区大小
#定义最大数量项目10
#根据第3行定义最大项目
静态字符*数组[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW];
#定义ITOA_基(sizeof(无符号)*字符位+1)
字符*itoa_基(字符*,整数,整数);
#定义TO_BASE(x,b)itoa_BASE((char[itoa_BASE_N]){0},(x),(b))
字符*itoa_基(字符*s,整数x,整数基){
s+=ITOA_BASE_N-1;
*s='\0';
如果(base>=2&&base首先,这:

(char [ITOA_BASE_N]){0}
与golang不同,它不会为您获取字符数组的新实例。因此,每次调用itoa(),您都是使用相同的字符数组来调用它。更糟糕的是,字符数组占用了一个可回收的堆栈地址[其范围仅限于该内部循环],所以很快就可以用随机的东西重写它。不过,它是非常一致的;我将给出它

将调用更改为:

array[i][j] = strdup(TO_BASE(count, 16));
在顶部添加一个#include可以生成您想要的输出

如果应用程序中不允许动态分配,则必须使用静态分配方案,您可以创建一个有界版本的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;
}
char*strnew(char*s){
静态字符strspace[ITOA_BASE_N*MAX_NUM_ITEMS*MAX_ITEM_PER_ROW];
静态字符*strnext=strspace;
如果(strlen+strspace>=&strspace[sizeof strspace]){
s=“”;/*可能会有更聪明的事情发生*/
}否则{
strcpy(strnext,s);
s=strnext;
strnext+=strlen(strnext)+1;
}
返回s;
}
你可以用它来代替strdup。如果你帮下一个人一个忙,使用一个更具描述性的概念,比如基于计算的MAX_STRING_SPACE;而不是插入一个“坏值”,引起某种异常,我相信他们会很感激的。

问题在于:

itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
          ^^^^^^^^^^^^^^^^^^^^^^^
您正在分配一个临时数组(在堆栈上),该数组仅在包含表达式语句的结尾处有效。因此,当打印它们时,存储在矩阵中的指针将悬空。编译器最终要做的是为每次调用重用相同的内存,因此字符串最终会被覆盖

您可以改为使用数组的静态矩阵,而不是指针:

static char array[MAX_NUM_ITEMS][MAX_ITEM_PER_ROW][ITOA_BASE_N];
然后第一个循环中的调用变为

itoa_base(array[i][j], count, 16);
您还需要“修复”
itoa_base
,以便将结果放在数组的前面而不是后面。显而易见的方法是使用递归循环,如:

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;
}
char*itoa_base(char*s,int x,int base){
if(base>=2&&base=base)
s=itoa_基准(s,x/基准,基准);
*s++=“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”[x%碱基];
}
*s='\0';
返回s;
}

您没有为字符串分配任何内存-它们只是未初始化的指针。我建议您在编译器调用时启用-Wall和/或-pedantic。我知道它们是未初始化的指针,但我正在使用EDK,因此不确定如何使用动态内存分配。有没有办法使用静态数组来实现相同的结果t?@PaulR
(char[ITOA_BASE_N]){0}
当然是数组类型的复合文字。当它出现在块范围内时,如OP的代码中,它所代表的数组具有自动存储持续时间。如OP的代码中所使用的,它在每次出现时都会产生一个语义不同的对象。但代码随后会在这些对象的生命周期结束后尝试使用这些对象,生成UB。这可能会产生重用同一对象的外观。