Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.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_Memory Management - Fatal编程技术网

C 这是优化内存使用的正确方法吗?

C 这是优化内存使用的正确方法吗?,c,memory-management,C,Memory Management,我的目标是优化内存使用。。。我从未在任何教程中看到过它,这让我觉得这不是正确的方法 #include <stdio.h> #include <string.h> #include <stdlib.h> struct Player { char* username; int hp; int mp; }; int main(void) { struct Player test, *p = &test; p->

我的目标是优化内存使用。。。我从未在任何教程中看到过它,这让我觉得这不是正确的方法

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

struct Player {
    char* username;
    int hp;
    int mp;
};

int main(void) {
    struct Player test, *p = &test;
    p->username = (char*)malloc(50 * sizeof(char));
    scanf("%s", p->username);
    p->username = realloc(p->username, (strlen(p->username) + 1) * sizeof(char));   
    printf("%s", p->username);
    return 0;
}
一些提示:

示例代码太小,不重要

永远不要用malloc来做你永远想要的事情。相反,预先分配,例如作为全局变量或如果它足够小,则使用局部变量以避免malloc的开销。例如:

不要把数据到处传播。您希望所有数据都位于同一位置,且缓存线数量最少,同时使用的数据段彼此尽可能接近。一种方法是合并多个项目。例如:

struct Player {
    char username[50];
    int hp;
    int mp;
};

int main(void) {
    struct Player test, *p = &test;
如果某个东西最多占用50个字符的内存;不要费心使用realloc浪费CPU时间,并可能浪费更多内存。不要忘记malloc和realloc的内部代码将向每个分配的内存块添加元数据,这些内存块可能需要额外的16字节或更多

一般而言;对于性能,malloc和realloc以及新的和。。。应完全避免,尤其是大型项目。它们将数据随机传播到任何地方,破坏了获得良好局部性的任何希望,这对于最小化多个非常昂贵的事情非常重要—缓存未命中、TLB未命中、页面错误、交换空间使用等

注意:scanf和get也应该被禁止。它们无法防止缓冲区溢出,例如,当只有足够的内存分配给50个字符时,用户提供超过50个字符,目的是故意破坏/破坏其他数据,从而导致巨大的安全漏洞

优化内存使用的正确方法

临时重复使用的缓冲区通常是慷慨的,大小是固定的

为内存分配合适的大小对成员来说是有意义的。代码的用户名可以用于数百万struct Player

IOWs,对代码的可变大小方面使用分配。如果struct Player是用于两人国际象棋,则字符用户名[50]大小是有意义的。对于多玩家世界,char*是有意义的

而不是调用*OLC两次考虑一个正确大小的调用。

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

// Reasonable upper bound
#define USERNAME_SIZEMAX 50

struct Player {
  char* username;
  int hp;
  int mp;
};

int main(void) {
  puts("Enter user name");
  // Recommend 2x - useful for leading/trailing spaces & detecting excessive long inputs.
  char buf[USERNAME_SIZEMAX * 50];

  if (fgets(buf, sizeof buf, stdin) == NULL) {
    puts("No input");
  } else {
    trim(buf); // TBD code to lop off leading/trailing spaces
    if (!valid_name(buf)) {  // TBD code to validate the `name`
      printf("Bad input \"%s\"\n", buf);
    } else {
      struct Player test = { 0 }; // fully populate
      test.username = malloc(strlen(buf) + 1);
      // Maybe add NULL check here
      strcpy(test.username, buf);
      // Oh happy day!
      printf("%s", p->username);
      return EXIT_SUCCESS;
    }
  }
  return EXIT_FAILURE;
}

scanf%s,基本上是scanf衣服上的一个小玩意儿,几乎从来都不对。谢谢你的评论,我通常使用fGet。缺点是如果你经常使用它,可能会将可用内存碎片化。此外,可能会分配一个最小的块大小,比如说16字节或1024字节或其他什么,这会浪费精力。我会输入一个慷慨的本地字符串,该字符串将在函数退出时消失,并在结构中只分配一次内存,然后复制该字符串。请参阅strdup函数。@Brendan函数scanf确实提供了一种防止缓冲区溢出的方法。@WeatherVane:是的,从技术上讲,它有可选的支持,人们会忘记使用。u对于性能,malloc和realloc以及新的和。。。应该完全避免uu你应该/你建议我什么时候使用它们?另一件事,当我对char test[50]进行declat并在其中输入整数时,整数会像往常一样取2字节还是取1字节作为一个字符?@Mohamed:性能和开发时间之间总是有一个折衷。当开发人员的时间比性能更重要时,使用malloc之类的工具。备选方案取决于具体的场景,可能使用局部变量,可能使用类似objstack的东西,可能分配一个数组,然后管理数组项,可能实现您自己的支持内存池的堆,…-那么像这样,username将准确获得所需的存储量-为什么只对两个玩家使用这个没有意义-当您执行test.username=mallocstrlenbuf+1时;您分配了字符数组所需的字节数,因此假设输入为20个字符,它将分配21个字节,但如果输入为10个整数,这将需要20个字节,但该函数将只分配1个字节…不确定我的问题是否清楚here@Mohamed但如果输入是10个整数,则需要20个字节,这一点尚不清楚。用户输入仅限于字符。1234\n是5个字符。Moha\n为5个字符@\n是5个字符。用户输入应该只包含字符,但如果用户出于任何原因决定输入整数,则会产生问题,因此我认为必须首先检查输入是否仅由characters@Mohamed如果用户出于任何原因决定输入整数,->让我们看一个较低的级别。用户不能输入整数。用户可以输入3个字符,如“4”、“2”和“\n”。FGET将读取为3个字符,并形成一个由“4”、“2”、“n”组成的字符串,并附加一个“\0”。即使代码使用scanf%d和&x,3个字符的输入也会被读取为3个字符并转换为int 42。42在x处保存。代码无法控制用户输入。没有魔法可以阻止任何打字。代码可以接受文本输入并转换为int、double、string等。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Reasonable upper bound
#define USERNAME_SIZEMAX 50

struct Player {
  char* username;
  int hp;
  int mp;
};

int main(void) {
  puts("Enter user name");
  // Recommend 2x - useful for leading/trailing spaces & detecting excessive long inputs.
  char buf[USERNAME_SIZEMAX * 50];

  if (fgets(buf, sizeof buf, stdin) == NULL) {
    puts("No input");
  } else {
    trim(buf); // TBD code to lop off leading/trailing spaces
    if (!valid_name(buf)) {  // TBD code to validate the `name`
      printf("Bad input \"%s\"\n", buf);
    } else {
      struct Player test = { 0 }; // fully populate
      test.username = malloc(strlen(buf) + 1);
      // Maybe add NULL check here
      strcpy(test.username, buf);
      // Oh happy day!
      printf("%s", p->username);
      return EXIT_SUCCESS;
    }
  }
  return EXIT_FAILURE;
}