C:指针分配错误

C: wrong allocation of the pointer

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

例如:

"hello" --> "hello"

“你好”--> "hello"

"你好" --> "hello"

" " --> ""

这是我的代码:

#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;
}

调试没有报错什么的,但是我知道内存和堆有问题,不知道怎么排除。

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

请多多指教,谢谢

您必须在程序结束前释放 '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)

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

  • 首先:Trim 原始变量在其他变量中,所以有两个变量:第一个变量有一个带空格的字符串,第二个字符串将是第一个没有 start/end 空格的变量的内容。
  • 第二个:Trim自身内部的变量。

执行此操作的代码是:

#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] = '[=10=]';

  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. #include 指令丢失。您至少需要 stdlib.hstring.h
  2. main 被声明为 return int,但你从一个地方 returning NULLt(这是char*) 来自另一个地方。
  3. 它可能会或可能不会做它应该做的事情。它最多只删除开头的一个 space 和结尾的一个 space,而不是短语前后的所有 space,并且以一种不必要的复杂方式进行。

该程序似乎没有的一种错误是将数据写入任何内容的末尾。

您的代码中存在大量小错误,开头为:

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,此时你应该简单地操作ts的原始副本,删除两个leading/trailing空格,然后进行最后一次调用 reallocmalloc/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;
}

例子Use/Output

$ ./bin/str_trim_realloc
t: 'prova'

内存Use/Error检查

$ 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)