C Zeichenketten und Speicher

Gast #4106689
Lesenswert?
• ▲
▼
Hallo,

ich bin neu in der C-Programmierung, habe vorher nur in Java 
programmiert. Möchte gerne eine Datei zeilenweise auslesen und die 
Zeilen dann splitten. Mein bisheriger Code:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <assert.h>
5

6

7
char  *read_line(FILE *);
8
char **split    (const char *, const char *, int *);
9

10

11
int main(int argc, char *argv[])
12
{
13
  if (argc != 2) {
14
    printf("input file expected.\n");
15
    return EXIT_FAILURE;
16
  }
17

18
  FILE *input_file = fopen(argv[1], "r");
19
  if (NULL == input_file) {
20
    printf("couldn't open file %s.\n", argv[1]);
21
    return EXIT_FAILURE;
22
  }
23

24
  while (feof(input_file) == 0) {
25
    char *line = read_line(input_file);
26
    printf("%s\t%d\n", line, strlen(line));
27

28
    int num_tokens = 0;
29
    char **tokens = split(line, " ", &num_tokens);
30

31
    for (int i = 0; i < num_tokens; ++i) {
32
      printf("Token #%d: %s\t(%d)\n", (i + 1), tokens[i], strlen(tokens[i]));
33
      free(tokens[i]);
34
    }
35

36
    free(tokens);
37
    free(line);
38
  }
39

40
  fclose(input_file);
41

42
  return EXIT_SUCCESS;
43
}
44

45

46
char *read_line(FILE *input_file)
47
{
48
  assert (NULL != input_file);
49

50
  char *buffer = malloc(sizeof(char));
51
  assert (NULL != buffer);
52

53
  int length = 1;
54
  int index  = 0;
55

56
  int read = fgetc(input_file);
57
  while (EOF != read && '\n' != read) {
58
    if (index >= length) {
59
      length *= 2;
60
      buffer = realloc(buffer, length * sizeof(char) + 1);
61
      assert (NULL != buffer);
62
    }
63
    buffer[index] = read;
64
    ++index;
65

66
    read = fgetc(input_file);
67
  }
68

69
  buffer[index] = '\0';
70
  return buffer;
71
}
72

73

74
char **split(const char *str, const char *delimiters, int *num_tokens)
75
{
76
  assert (NULL != str);
77
  assert (NULL != delimiters);
78
  assert (NULL != num_tokens);
79

80
  char *string = malloc(strlen(str) + 1);
81
  assert (NULL != string);
82
  strcpy(string, str);
83

84
  char **tokens = malloc(sizeof(char *));
85
  assert (NULL != tokens);
86

87
  int number_tokens = 1;
88
  int index = 0;
89

90
  char *token = strtok(string, delimiters);
91
  while (NULL != token) {
92
    if (index >= number_tokens) {
93
      ++number_tokens;
94
      tokens = realloc(tokens, number_tokens * sizeof(char *));
95
      assert (NULL != tokens);
96
    }
97
    tokens[index] = malloc(strlen(token) + 1);
98
    assert (NULL != tokens[index]);
99
    strcpy(tokens[index], token);
100

101
    ++index;
102
    token = strtok(NULL, delimiters);
103
  }
104

105
  *num_tokens = number_tokens;
106
  return tokens;
107
}
Es scheint zu funktionieren, wie ich es mir vorgestellt hatte. 
Allerdings bin ich mir unsicher, ob ich den Speicher "richtig und 
komplett" freigegeben habe. Insbesondere habe ich Bedenken bei der 
split-Funktion, ob ich dort "string" noch freigeben muss. strtok 
verändert "string" ja und liefert Zeiger aus selbigen zurück. Reicht es 
dann, wenn ich das jeweilige aktuelle Token freigebe und nicht "string" 
als Ganzes am Ende der Funktion?

Und eine kleine Frage nebenbei: Für diese Kleinigkeit wirkt mir das 
Programm ziemlich "aufgebläht", obwohl ich von Java komme. Gibt es eine 
elegante Implementation für diese Funktionalität?

Ich bin für jede Antwort dankbar.
#4106819
Lesenswert?
• ▲
▼
toboe schrieb:
> strtok
> verändert "string" ja und liefert Zeiger aus selbigen zurück. Reicht es
> dann, wenn ich das jeweilige aktuelle Token freigebe und nicht "string"
> als Ganzes am Ende der Funktion?

Du darfast nur genau das freigeben, was du auch allokiert hast.

Also wenn du einen langen String allokierst und dann stückweise 
verarbeitest, musst du trotzdem genau den Stringanfang freigeben, das 
gilt dann für den gesamten Speicher wie er zuerst allokiert wurde.

Beim Versuch, stückweise freizugeben, was du in einem Rutsch allokiert 
hast, stürzt im besten Fall dein Programm ab.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.