CBFalconer wrote:
Tatu Portin wrote:
Have this kind of struct:
typedef struct {
char **user_comments;
/* ... */
} vorbis_comment;
/* prototype */
char * read_vorbis_string
( FILE *sc);
/* problem */
vc.user_comments[i] = read_vorbis_string (sc);
'read_vorbis_string' returns a pointer to a calloced string. This
function works for sure.
But the problem is, that 'vc.user_comments[i] = string;' is not
the right way to assing the address of the 'string' to the pointer
array 'vc.user_comments'. What is?
You haven't shown a complete compilable program, which forces
anyone replying to make assumptions (or to ignore you). There is
no declaration of vc. Assuming one exists in scope, of the form:
vorbis_comment vc;
vc.user_comments is of type char **, i.e a pointer to a pointer to
a char. It is uninitialized, and any use of it will cause
undefined behaviour. Don't ask me what you should initialize it
to, since you didn't bother making your program and specifications
complete. I suspect you want a linked list rather than an array.
Here is the complete working program. (compiled -Wall -pedantic)
/* Start Of File */
/* Public Domain */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
/* CDmaker
* Purpose is to correctly rip tags from Ogg Vorbis files for
* reproduction in printable form for CD distribution.
*/
typedef struct {
char **user_comments;
int *comment_wds;
int comments;
char *vendor;
} vorbis_comment;
/* 'read_comments' is a hack.
* It does not work by the specification.*/
char * read_vorbis_string
( FILE *sc);
int wind_till
( const char *ident
, FILE *sc);
vorbis_comment read_comments
( const char *scname);
int print_comments
( const vorbis_comment vc);
int main
( int argc
, char *argv[])
{
vorbis_comment vc;
vc = read_comments (argv[1]);
print_comments (vc);
return 0;
}
char * read_vorbis_string
( FILE *sc)
{
register int i;
int wd;
char *str;
char ch;
if (fread (&wd, sizeof (int), 1, sc) != 1)
return NULL;
str = (char *) calloc (wd + 1, sizeof (int));
if (str == NULL)
return NULL;
for (i = 0 ; i < wd ; i++) {
ch = fgetc (sc);
if (ch == EOF)
break;
str[i] = ch;
}
str[wd + 1] = '\0';
return str;
}
int wind_till
( const char *ident
, FILE *sc)
{
register int i;
int ch = '\0';
if (ident[0] == '\0')
return 0;
while (1) {
for (i = 0 ; ident[i] == ch ; i++) {
if (ident[i + 1] == '\0')
return 0;
ch = fgetc (sc);
if (ch == EOF)
return 2;
}
ch = fgetc (sc);
if (ch == EOF)
return 1;
}
return 3;
}
vorbis_comment read_comments
( const char *scname)
{
/* After second 'vorbis' string comes the width (int) of VENDOR string.
* Then comes the VENDOR string itself.
* After VENDOR string comes the number (int) of comments.
* After the number of comments comes the width (int) of first user comment.
* After the first user comment comes the width (int) of the second user comment.
*/
register int i;
vorbis_comment vc;
FILE *sc;
char *ident = "vorbis";
sc = fopen (scname, "rb");
assert (sc != NULL);
assert (!wind_till (ident, sc));
assert (!wind_till (ident, sc));
vc.vendor = read_vorbis_string (sc);
assert (vc.vendor != NULL);
assert (fread (&vc.comments, sizeof (int), 1, sc) == 1);
/* Allocate memory for pointers */
vc.user_comments = (char **) calloc (vc.comments + 1, sizeof (char *));
assert (vc.user_comments != NULL);
/* Allocate memory for comment lenghts */
vc.comment_wds = (int *) calloc (vc.comments + 1, sizeof (int));
assert (vc.comment_wds != NULL);
for (i = 0 ; i < vc.comments ; i++) {
vc.user_comments[i] = read_vorbis_string (sc);
assert (vc.user_comments[i] != NULL);
vc.comment_wds[i] = strlen (vc.user_comments[i]);
}
vc.comment_wds[vc.comments + 1] = 0;
return vc;
}
int print_comments
( vorbis_comment vc)
{
register int i;
printf ("%s, %d comments\n", vc.vendor, vc.comments);
for (i = 0 ; i < vc.comments ; i++) {
printf ("%d: \t%s\n"
, vc.comment_wds[i]
, vc.user_comments[i]
);
}
return i;
}
/* End Of File */