Tab writer in C

May 28, 2018 at 4:21pm
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 May 28, 2018 at 4:22pm
May 28, 2018 at 4:59pm
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).
May 29, 2018 at 4:06pm
Oh, okay. That makes sense.

Thank you again Ganado.
May 29, 2018 at 5:50pm
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 May 29, 2018 at 6:05pm
May 29, 2018 at 7:59pm
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;
}
Jun 1, 2018 at 2:07am
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.