Tab writer in C

Getting strange characters in my first print statement, but on none of the others. Also, code will not progress past the getName() call in line 58. Unable to figure out either of these issues.

This is intended to be a tab writer for guitars.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  /* PROJECT Guitar tab writer
 * Author  Chris Bowers
 * Version 1.0 May 22, 2015
 */

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

#define TRIAL_SIZE 16
#define NUM_STRINGS 5
typedef struct {
    char* text;
    int length;
    int size;
} Tab; 

void initializeTabSize(Tab* t) {
    t->text = malloc(sizeof(char) * TRIAL_SIZE);
    t->size = TRIAL_SIZE;
    if (t->text)
        printf("String successfully allocated\n");
    else
        printf("That didn't work\n");
}

void tabTemplate(Tab* t) {
    int i = 0;
    t->text[0] = '|';
    t->text[t->size] = '|';
    for (i = 1; i < (t->size); i++)
        t->text[i] = '-';
    printf("%s\n", t->text);
}

char* getName(void) {
    int i = 0;
    char* fileName;
    printf("Enter name of file >> ");
    while (scanf("%c", &fileName[i]))
        i++;
    return fileName;
}

void writeTabToFile(FILE* tabFP, Tab* t, int lines) {
    int i = 0;
    for (i = 0; i < lines; i++)
        fprintf(tabFP, "%s", t->text);
}

int main(void) {
    int i = 0;
    FILE* tabFP;
    Tab tab1[NUM_STRINGS]; // configure for number of strings in later version
    for (i = 0; i < NUM_STRINGS; i++)
        initializeTabSize(&tab1[i]);
    for (i = 0; i < NUM_STRINGS; i++)
        tabTemplate(&tab1[i]);
    tabFP = fopen(getName(), "a");
    for (i = 0; i < NUM_STRINGS; i++)
        writeTabToFile(tabFP, &tab1[i], NUM_STRINGS);
    fclose(tabFP);
    return EXIT_SUCCESS;
}
Last edited on
C strings (char buffers) must be null-terminated to be printed correctly. When you make your own string allocated from a char* malloc, you have to make the last index be the null character '\0'.

1
2
3
4
5
6
7
8
char* getName(void) {
    int i = 0;
    char* fileName;
    printf("Enter name of file >> ");
    while (scanf("%c", &fileName[i]))
        i++;
    return fileName;
}

You never initialize (allocate) fileName. This will either result in junk or a crash (undefined behavior).
Oh, okay. That makes sense.

Thank you again Ganado.
Actually, I have something strange with my file name. It comes out as 3 bad characters despite receiving the name well.

I get a warning: function return address of local variable
Research makes it seem I need to allocate memory to the function, but this was not covered in the class I took. If you could point me to a resource for this concept, I would be grateful.

Here is my new code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/* PROJECT Guitar tab writer
 * Author  Chris Bowers
 * Version 1.0 May 22, 2015
 */

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

#define TRIAL_SIZE 16
#define NUM_STRINGS 5
#define MAX_NAME_SIZE 32
typedef struct {
    char* text;
    int length;
    int size;
} Tab; 

void initializeTabSize(Tab* t) {
    t->text = malloc(sizeof(char) * TRIAL_SIZE);
    t->size = TRIAL_SIZE;
    if (t->text)
        printf("String successfully allocated\n");
    else
        printf("That didn't work\n");
}

void tabTemplate(Tab* t) {
    int i = 0;
    t->text = malloc(sizeof(char) * TRIAL_SIZE);
    t->text[0] = '|';
    t->text[t->size] = '|';
    for (i = 1; i < (t->size); i++)
        t->text[i] = '-';
    printf("%s\n", t->text);
}

char* getName(void) {
    int i = 0;
    char fileName[MAX_NAME_SIZE];
    printf("Enter name of file >> ");
    scanf("%c", &fileName[0]);
    for (i = 1; fileName[i - 1] != '\n' && i < MAX_NAME_SIZE; i++)
        scanf("%c", &fileName[i]);
    fileName[32] = '\0';
    printf("\n%s\n", fileName);
    return fileName;
}

void writeTabToFile(FILE* tabFP, Tab* t, int lines) {
    int i = 0;
    for (i = 0; i < lines; i++)
        fprintf(tabFP, "%s", t->text);
}

int main(void) {
    int i = 0;
    FILE* tabFP;
    Tab tab1[NUM_STRINGS]; // configure for number of strings in later version
    for (i = 0; i < NUM_STRINGS; i++)
        initializeTabSize(&tab1[i]);
    for (i = 0; i < NUM_STRINGS; i++)
        tabTemplate(&tab1[i]);
    tabFP = fopen(getName(), "a");
    for (i = 0; i < NUM_STRINGS; i++)
        writeTabToFile(tabFP, &tab1[i], NUM_STRINGS);
    fclose(tabFP);
    return EXIT_SUCCESS;
}
Last edited on
I rather would let the caller provide a buffer for the filename like so:
1
2
3
4
5
int get_filename(char *buffer, size_t size)
{
   /* read filename into buffer
  return 1 in case the filename was entered otherwise 0 */
}

In this way the caller would not need to delete the memory.
In case you have to use dynamic memory you can do it like this:
1
2
3
4
5
6
7
8
9
10
char* get_filename()
{
  char fname = malloc(some size);
  if (name  == NULL)
    return NULL;

  /* read  filename into fname */ 

  return fname;
}
Sorry for the late reply. I'll be implementing this tomorrow and will see how it goes.

Thanks Thomas1965.
Topic archived. No new replies allowed.