C:错误分配指针[重复]

问题描述 投票:0回答:4

这个问题在这里已有答案:

我有一个char数组,我想删除单词(或短语)之前或之后的空白,而不是中间。

例如:

“你好” - >“你好”

“你好” - >“你好”

“你好” - >“你好”

" " --> ""

这是我的代码:

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

int main(void) 
{
    char s[] = " prova ";
    char *t = NULL;
    if (s == NULL)
    {
        t = NULL;
    }
    else {
        int n = strlen(s);
        t = malloc(sizeof(char)* (n + 1));
        for (int i = 0; i <= n; ++i)
        {
            t[i] = s[i];
        }
        int k = 0;
        if (s[0] == ' ')
        {
            ++k;
            t = realloc(t, sizeof(char)*n);
            for (int i = 0; i <= n - 1; ++i)
            {
                t[i] = s[i + 1];
            }
        }

        if (s[n - 1] == ' ')
        {
            if (k == 1)
            {
                int j = 0;
                t = realloc(t, sizeof(char)*(n - 1));
                for (int i = 0; i <= n - 2; ++i)
                {
                    t[i] = t[i];
                    j = i;
                }
                t[j] = 0;
            }
            else
            {
                int j = 0;
                t = realloc(t, sizeof(char)*n);
                for (int i = 0; i <= n - 1; ++i)
                {
                    t[i] = t[i];
                    j = i;

                }
                t[j] = 0;
            }
        }
    }
    return t;
}

调试不会给我错误或其他东西,但我知道内存和堆有问题,我不知道如何删除它。

我在这个平台上寻找与我类似的其他问题并且它们存在,但没有一个答案解决了我的问题。

请给我一些建议,谢谢

c arrays visual-studio-2017 out-of-memory heap-corruption
4个回答
1
投票

从以下开始,代码中存在大量小错误:

if (s == NULL)

s永远不会是NULL,除非您的编译器完全损坏或者您的堆栈少于8字节。

接下来,在删除前导空格之前,您需要realloc,例如

        t = realloc(t, sizeof(char)*n);
        for (int i = 0; i <= n - 1; ++i)

未指定调用realloc截断哪些(如果有)字节。相反,你需要在调用t之前对realloc进行操作以删除前导空格(然后你仍然不能保证任何内存都会被调整)

接下来,你多次调用realloc,当你应该简单地操作st的原始副本来删除前导/尾随空格,然后在最后调用realloc。从效率的角度来看,malloc/realloc是相对昂贵的电话,不应该重复调用。

重新排列逻辑,您可以这样做:

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

int main(void) 
{
    char s[] = " prova ";
    char *t = NULL;
    size_t n = strlen(s);           /* strlen returns size_t */
    int k = 0;

    t = malloc (n + 1);             /* sizeof(char) is 1 */
    if (t == NULL) {                /* validate ALL allocations */
        perror ("malloc-t");
        return 1;
    }

    for (size_t i = 0; i <= n; i++) /* copy s to t */
        t[i] = s[i];

    while (t[k] == ' ')             /* count leading whitespace */
        k++;

    for (size_t i = 0, j = k; j <= n; i++, j++) /* remove whitespace */
        t[i] = t[j];

    n -= k;                         /* update n */

    while (n && t[n - 1] == ' ')    /* remove trailing whitespace */
        t[n-- - 1] = 0;

    void *tmp = realloc (t, n + 1); /* realloc with tmp varaible */
    if (tmp == NULL) {              /* validate ALL allocations */
        perror ("realloc-t");
        return 1;
    }
    t = tmp;                        /* assign new block to t */

    printf ("t: '%s'\n", t);
    free (t);                       /* don't forget to free memory */

    return (int)n;
}

示例使用/输出

$ ./bin/str_trim_realloc
t: 'prova'

内存使用/错误检查

$ valgrind ./bin/str_trim_realloc
==26078== Memcheck, a memory error detector
==26078== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26078== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==26078== Command: ./bin/str_trim_realloc
==26078==
t: 'prova'
==26078==
==26078== HEAP SUMMARY:
==26078==     in use at exit: 0 bytes in 0 blocks
==26078==   total heap usage: 2 allocs, 2 frees, 14 bytes allocated
==26078==
==26078== All heap blocks were freed -- no leaks are possible
==26078==
==26078== For counts of detected and suppressed errors, rerun with: -v
==26078== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

1
投票

有两种方法可以做到这一点:

  • 第一:在其他变量中修剪原始变量,因此有两个变量:第一个变量有一个带空格的字符串,第二个字符串是第一个变量的内容,没有开始/结束空格。
  • 第二:修改变量本身。

这样做的代码是:

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

size_t trimInOtherVariable(char *out, size_t len, const char *str)
{
  if(len == 0)
    return 0;

  const char *end;
  size_t out_size;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
  {
    *out = 0;
    return 1;
  }

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;
  end++;

  // Set output size to minimum of trimmed string length and buffer size minus 1
  out_size = (end - str) < len-1 ? (end - str) : len-1;

  // Copy trimmed string and add null terminator
  memcpy(out, str, out_size);
  out[out_size] = 0;

  return out_size;
}



char *trimInSameVariable(char *str)
{
  char *end;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
    return str;

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;

  // Write new null terminator character
  end[1] = '\0';

  return str;
}



int main(void)
{
    // Declare string for trimming
    char buffer[] = "    pr ova    ";
    size_t size;

    // Declare pointers which will store trimmed variable
    char *stringWithSpaces = (char *) malloc( sizeof(char)*(strlen(buffer)+1) );
    char *stringWithoutSpaces = (char *) malloc( sizeof(char)*(strlen(buffer)+1) );

    // Check if allocating memory is OK. Then copy string to trim inside pointer
    if (stringWithSpaces == NULL || stringWithoutSpaces == NULL)
        return -1;
    else
        strcpy(stringWithSpaces, buffer);

    // Way 1: Trim 'stringWithSpaces' inside 'stringWithoutSpaces'
    size = trimInOtherVariable(stringWithoutSpaces, strlen(buffer), stringWithSpaces);
    // Way 2: Trim 'stringWithSpaces' inside itself
    stringWithSpaces = trimInSameVariable(stringWithSpaces);

    // Show trimmed strings
    printf (
        "String trimmed in other variable: \"%s\"\n"
        "String trimmed in same variable: \"%s\"\n"
        , stringWithoutSpaces, stringWithSpaces
    );

    // End function
    return 0;
}

希望这对你有所帮助。


1
投票

您的程序至少包含以下错误:

  1. #include指令丢失了。你至少需要stdlib.hstring.h
  2. main被宣布返回int,但是你从一个地方返回NULL并从另一个地方返回tchar*类型)。
  3. 它可能会或可能不会做它应该做的事情。它只删除开头和最后一个空格中的一个空格,而不是短语之前或之后的所有空格,并且以不必要的复杂方式进行。

这个程序似乎没有一种错误就是将数据写入任何结尾。


0
投票

你必须在程序结束前释放't'。也许您需要在代码中进行一些重构:

#include <stdlib.h> //realloc
#include <string.h> // memcpy

char *remove_space(char *s) {
  char *t = 0;
  if (s == 0) {
    return 0;
  } else {
    int n = strlen(s);
    t = malloc(sizeof(char) * n + 1);
    for (int i = 0; i <= n; ++i) {
      t[i] = s[i];
    }
    int k = 0;
    if (s[0] == ' ') {
      ++k;
      t = realloc(t, sizeof(char) * n);
      for (int i = 0; i <= n - 1; ++i) {
        t[i] = s[i + 1];
      }
    }

    if (s[n - 1] == ' ') {
      if (k == 1) {
        int j = 0;
        t = realloc(t, sizeof(char) * n - 1);
        for (int i = 0; i <= n - 2; ++i) {
          t[i] = t[i];
          j = i;
        }
        t[j] = 0;
      } else {
        int j = 0;
        t = realloc(t, sizeof(char) * n);
        for (int i = 0; i <= n - 1; ++i) {
          t[i] = t[i];
          j = i;
        }
        t[j] = 0;
      }
    }
  }

  return t;
}

int main(void) {
  char s[] = " prova ";

  free(remove_space(s));

  return 0;
}

检查valgrind:

valgrind --leak-check=full --show-reachable=yes ./program
==8753== Memcheck, a memory error detector
==8753== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8753== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8753== Command: ./program
==8753== 
==8753== 
==8753== HEAP SUMMARY:
==8753==     in use at exit: 0 bytes in 0 blocks
==8753==   total heap usage: 3 allocs, 3 frees, 21 bytes allocated
==8753== 
==8753== All heap blocks were freed -- no leaks are possible
==8753== 
==8753== For counts of detected and suppressed errors, rerun with: -v
==8753== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

© www.soinside.com 2019 - 2024. All rights reserved.