4

I am a relatively new programmer in C and I'm trying to simply print out the content from an input file onto my screen. I have to use dynamic memory allocation and the issue I am facing is that if the number of letters in my string is >8 it overwrites it.

int main(){
FILE *input = fopen("inpit.txt","r");
int b;
char **aPtr;
int i = 0;
int j = 0;
fscanf(input,"%d",&b); //takes first value from input file which tells me number of strings in the file
aPtr = (char **)malloc(sizeof(char *)*b); 
for(i=0;i<b;i++) {
    aPtr[i]=(char *)malloc(sizeof(char));
}
for(i = 0;i < b;i++){
    fscanf(input,"%s",&aPtr[i]);
}
for(i = 0;i < b;i++){
    printf("Address %d = %d\n",i,&aPtr[i]);
}

for(i = 0;i < b;i++){
    printf("%s\n",(aPtr+i));
}
return 0; }

My input into the file inpit1.txt is:

5
grapefruit
apple
Banana
monkey
orange

If I run the file. Everything will print out fine except grapefruit. Which will be overwritten to grapefruapple.

Any help would be appreciated. Thank you in advance.

peterh
  • 11,875
  • 18
  • 85
  • 108
L Lawliat
  • 137
  • 2
  • 11

4 Answers4

3

You have a problem with your malloc which is only allocating for one char here:

aPtr[i]=(char *)malloc(sizeof(char));

Try to add a given size to it:

aPtr[i]=(char *)malloc(sizeof(char)*20);

And it should work better

Note on the casting of malloc(): Casting malloc() is not necessary in c (unless dealing with extra-old standards [pre-1989]) and can hide errors. void* is automatically promoted to any other pointer type. However it is useful if compiling as C++, since your question included both C and C++ I thought it would be good to tell you about it.

EDIT: For further information on the cast of malloc() I just found this protected question here. Feel free to check it out.

Also you need to check that malloc() was successful (the result is !=NULL)

Finally your printf is not correct and should be printf("%s\n", aPtr[i]);

Community
  • 1
  • 1
LBes
  • 3,366
  • 1
  • 32
  • 66
3

Problems I see:

  1. You are not allocating enough memory for aPtr[i].

    aPtr[i]=(char *)malloc(sizeof(char));
    

    allocates memory for only one char. It's not enough to hold a string. You need something like:

    int arraySize = 20; // Make it large enough
    aPtr[i] = malloc(arraySize); // No need to use sizeof(char).
                                 // It is always 1
    
  2. Make sure that when you read the string, you don't overflow the array size. Instead of:

    fscanf(input,"%s",&aPtr[i]);
    

    use:

    fscanf(input,"%19s", aPtr[i]);
    //                  ^^^ Remove the & operator. That is wrong.
    //            ^^^ Add size to prevent overflow.
    
  3. You are using the wrong argument to the printf function. Instead of:

    printf("%s\n",(aPtr+i));
    

    use

    printf("%s\n", *(aPtr+i));
    //            ^^^ Missing pointer dereferencing operator
    

    or

    printf("%s\n", aPtr[i]);
    
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

The first comment on your question is right at the heart of the problem.
malloc(sizeof(char)) is really just malloc(1)

What you have done is...

Allocate an array of N character pointers

aPtr = (char **)malloc(sizeof(char *)*b); 

Allocate a single character to each pointer in the list

for(i=0;i<b;i++) {
  aPtr[i]=(char *)malloc(sizeof(char));
}

Copy a string of unknown length into the memory allocated to each pointer in the list.

for(i = 0;i < b;i++){
  fscanf(input,"%s",&aPtr[i]);
}

The memory allocated to each character pointer is likely to be close or contiguous to the memory allocated to its predecessor. Subsequent writes are likely to overwrite some portion of the preceding string. The the case of your example, there appears to be a sufficient gap between consecutively allocated blocks of memory that only the 'grapefruit' entry is long enough to be obviously trampled by it's neighbor.

Greg
  • 1,480
  • 3
  • 15
  • 29
0

There you go :) (I tried to explain in the comments)

int main() {

    FILE * pFile;
    char * buffer = NULL;
    size_t size = 0;
    ssize_t line_length;

    pFile = fopen("inpit.txt", "r");
    if (pFile != NULL) {
        int number_of_lines;
        fscanf(pFile, "%d", &number_of_lines);

        //create charcter pointers array to hold each line
        char* strings[number_of_lines];

        int i = -1;
        while ((line_length = getline(&buffer, &size, pFile)) != -1) {
            if (i != -1) { // skips first line because its number of lines (5)
                strings[i] = malloc(line_length * sizeof(char)); //allocate memory for the line
                sprintf(strings[i], "%s", buffer); //copy line from buffer to allocated space 
            }
            //incase file has more than it said
            if (i++ >= number_of_lines) { break; }
        }

        //Test print
        for (i = 0; i <= number_of_lines; i++) {
            printf("%s", strings[i]);
        }
        printf("\n");

        fclose(pFile);
        if (buffer) { free(buffer); }
    }
}
Lukas
  • 3,423
  • 2
  • 14
  • 26