1
  1. Hi there, I am new to C Programing and I am trying to make a Program to Read and Print text from standard input (file or keyboard) as part of my studies.
  2. The rules are:
    • use two function one for read and one for print.
    • read function should read into dynamic array or dynamic linked list of arrays.
    • read function should ignore enter character ('\n').
    • the user should be able to choose one of two data struct types option (array or linked list).
    • print function should print the text in lines of 60characters.
    • the first memory allocation should be at the main function.
  3. I have been trying to solve this out for few weeks but getting stuck, any step will be helpful.
  4. I am still having problems in both function readText and printText
  5. There are some code that have not written yet because I could not check print function without make read function work out.
  6. The First problem is that the read function failed to allocate new memory after 120 characters.
  7. My Code:
/* This program will pick up text from the standard input store him at one of two data structure types and print it according to the following rules:
 8. every printed line will be at the size of 60 characters.
 9. if there is no more memory to allocate the program will print the text that stored until this moment.
 */

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

#define LINE_SIZE 60
#define BUFFER 1
#define LINKED_LIST 2

/* function prototype */

void readText(void *pointer,int dataStructType); /* function to read text from standard input and store it in a data structure */
void printText(void *pointer,int dataStructType); /* function to print text from a given data structure */

struct linkedList
{
    char data[LINE_SIZE];
    struct linkedList * next;
};

int main()
{ /* start of main function */

    void *pointer = NULL;
    int dataStructType = 0;
   /* message that asking the user to choose one of two functions to use */

    printf("please insert the number of the data structure you want to use and press enter:\n1 - Buffer.\n2 - Linked List.\n");
    scanf("%d",&dataStructType); /* collect the user input into dataStructType variable */

    while(dataStructType != BUFFER && dataStructType != LINKED_LIST) /* while the user put in an invalid option */
    {
        printf("invalid input!\tplease try again.\n\n"); /* print error message to the user and return the process */
        printf("please insert the number of the data structure you want to use and press enter:\n1 - Buffer.\n2 - Linked List.\n");
        scanf("%d",&dataStructType);
    }

    if(dataStructType == BUFFER) /* if the user chose buffer as the data structure type */
    {
        printf("you have chosen option one - Buffer data structure type.\n");
        pointer = (char*) calloc(LINE_SIZE, sizeof(char));
        if(!pointer) /* if pointer is NULL */
        {
            printf("error!\t memory allocation failed.\t please try again later."); /* error message for the user */
            return 0; /* exit main function and the program */
        }else /* if the memory allocation succeeded */
        {
            readText(pointer,dataStructType); /* call readText function with BUFFER dataStructType */
            printText(pointer,dataStructType); /* call printText function with BUFFER dataStructType  */
        }
    }else /* if the user chose linked list as the data structure type */
    {
        printf("you have chosen option two - Linked List data structure type.\n");

        struct linkedList * head = NULL;
        head = calloc(1, sizeof(struct linkedList));

        if(!head) /* if head is NULL */
        {
            printf("error!\t memory allocation failed.\t please try again later."); /* error message for the user */
            return 0; /* exit main function and the program */
        }else /* if the memory allocation succeeded */
        {
            pointer = head;
            readText(&pointer,dataStructType); /* call readText function with linkedList dataStructType */
            printText(pointer,dataStructType); /* call printText function with linkedList dataStructType  */
        }
    }
    return 0;
} /* end of main function */

/* readText function.
 *
 * mission: read text from standard input and store it in a data structure by the following rules:
 *      if there is not enough memory the function will try to find new memory for the structure.
 *      if the function cant find memory she will store the text until the memory is full and print him.
 *
 * parameters:
 *      pointer - points to the pointer that points to the start of the data structure.
 *      dataStructType - an integer that represent the data struct type.
 *
 * available data structures:
 *      1 - Buffer - Array.
 *      2 - linkedList - Linked List.
 */

void readText(void *pointer,int dataStructType)
{ /* start of readText function */
    int cnt = 0; /* count the number of characters collected into the the array until the end of the specific line (limited for 60 characters for a line) */
    int currentCell = 0; /* counter to count the collected characters **/
    char c; /* character variable to collect characters from the input */
    int lines = 1; /* lines counter */
    char *holder = NULL; /* temporary pointer to a new line */
    printf("please enter your text and in the end press cntrl+d\n");
    if(dataStructType == BUFFER) /* if the structure type is a buffer. */
    {
        while((c = getchar()) != EOF)
        {
            if (c != '\n') /* if the character is '\n' skip the character */
            {
                if (cnt == LINE_SIZE - 1) /* if this is the sixty character (starts from index 0) */
                {
                    cnt = 0; /* restart counter value */
                    lines++; /* add a "line" to calculate the memory size */
                    holder = (char *)realloc(pointer,  (lines * LINE_SIZE) * sizeof (char)); /* reallocate new memory including memory for a new "line" */
                    if (holder == NULL) /* if the memory allocation failed */
                    {
                        printf("error!\t memory allocation failed.\n the program will now print the successfully collected text.\n"); /* message for the user */
                        printf("after printing the collected text the program will be finished\n"); /* message for the user */
                        pointer = (pointer - (lines * LINE_SIZE)); /* re-aim the pointer to the buffer start */
                        printText(pointer, BUFFER); /* call printText function to print the collected text */
                    } else /* if the memory allocation succeeded */
                    {
                        free(pointer); /* free the old array memory */
                        pointer = holder; /* re-aim the pointer to the start of the new allocated memory */
                        /* pointer = (pointer + ((lines - 1) * LINE_SIZE)); /* re-aim the pointer to the start of the "new line" on the new allocated memory */
                    }
                } /* if we did not finished to collect text into a line and the character is not '\n' */
                *(char*)(pointer + currentCell) = c; /* place the character in the current cell of the array */
                cnt++; /* increment counter by one */
                currentCell++; /* increment current cell counter by one */
            }
        } *(char*)(pointer + currentCell) = c; /* place the character in the current cell of the array */
    }else /* if the structure type is a linked list. */
    {

    }
} /* end of readText function */



void printText(void *pointer,int dataStructType)
{
    if (dataStructType == BUFFER) /* if the data structure is buffer */
    {
        register int cnt = 0; /* count the number of characters printed from a specific line (limited for 60 characters for a line) */
        register int currentCell = 0; /* counter to count the collected characters */
        while (*(char*)pointer != EOF) /* if its the end of the file finish the printing */
        {
            if (cnt == 59) /* if we printed 60 characters print an enter for a new line */
            {
                printf("\n");
                cnt = 0;
            } else /* if there is more characters to print until 60 characters */
            {
                printf("%c", *(char*)(pointer + currentCell)); /* print the character */
                cnt++; /* count another character that was printed */
                currentCell++; /* increment current cell counter by one */
            }
        }
    } /* else if the data structure is a linked list */
}
CrazyTux
  • 204
  • 2
  • 12

2 Answers2

1

Congratulations on working with C, once you're over the learning curve, your experience in it will be invaluable!

Some hints:

  • if you want to read into something dynamic, consider these options: provide a ** parameter, or return a * so that the caller can link to the memory returned by realloc
  • you're using free incorrectly, realloc handles freeing any memory
  • printf has length format specifiers which work with strings, and the function returns the number of bytes written
Dharman
  • 30,962
  • 25
  • 85
  • 135
Yimin Rong
  • 1,890
  • 4
  • 31
  • 48
  • Hey there and thank you for your answer! want to see if i got that clear: - i need to send a **pointer to readText for a correct link between realloc and the first memory allocated in the main function. - i can make readText function return and integer with the array size and then printf can print the exec size from the array start point (will it work for linked list also?) - realloc is automatic freeing the memory, just saw that i wrote free(pointer) when i was trying to write free(holder) because he is not needed if the memory allocation Succeeded. – CrazyTux Jun 08 '21 at 13:09
  • about the pointer "free" function, i want to hold the "old" memory till the new memory allocated and then free the pointer and switch him with the "holder" pointer. because if I will not hold the old memory pointer i could lose the old memory pointer. – CrazyTux Jun 08 '21 at 13:16
  • `realloc` is already doing that. If `realloc` can't expand the existing space, if will find a new space and move the contents. You need to return that pointer. – Yimin Rong Jun 08 '21 at 13:19
  • I am sorry for my miss understanding but I read that realloc returns A pointer to the start of the allocated memory, or NULL if an error occurred (errno is set), well if there is no memory to allocate I will lose the text that I have read till the memory allocate failed and I will not be able to print the text that I already read into the array or the linked list , am I wrong ? – CrazyTux Jun 08 '21 at 13:22
  • I have fixed the readText function by deleting the free(); function and also use *(((char*)pointer) + currentCell) = c; instead of *(char*)(pointer + currentCell) = c; when collecting a character into the dynamic array. – CrazyTux Jun 08 '21 at 16:39
  • Regarding keeping track of the old pointer, you're right, if you want the program to continue functioning after a failed allocation, then yes, you need to save it, but also let the caller know that the program is in "safe mode" and not try to read any more data. Note that in some systems a failed allocation generates an exception and your error handling code may never be used. – Yimin Rong Jun 08 '21 at 17:45
1
  1. I made a program that works! (sorry excited a little bit).
  2. Well this is the mistakes I found:
    • using free(); function in an unneeded spot. (following the reference of Yimin Rong).
    • Incorrect use of brackets while trying to get the pointer point value.
    • Incorrect use of printf(); function, instead I used putchar(); function to print the characters.
  3. Added free methods by David C. Rankin advice.
  4. Completed the linked list part in both functions.

Here is the completed code:

/* This program will pick up text from the standard input store him at one of two data structure types and print it according to the following rules:
 * every printed line will be at the size of 60 characters.
 * if there is no more memory to allocate the program will print the text that stored until this moment.
 */

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

#define LINE_SIZE 60
#define BUFFER 1
#define LINKED_LIST 2

/* function prototype */

void readText(void *pointer,int dataStructType); /* function to read text from standard input and store it in a data structure */
void printText(void *pointer,int dataStructType); /* function to print text from a given data structure */

struct Node
{
    char data[LINE_SIZE];
    struct Node * next;
};

int main()
{ /* start of main function */

    void *pointer = NULL;
    struct Node * head = NULL;
    int dataStructType = 0;
   /* message that asking the user to choose one of two functions to use */

    printf("please insert the number of the data structure you want to use and press enter:\n1 - Buffer.\n2 - Linked List.\n");
    scanf("%d",&dataStructType); /* collect the user input into dataStructType variable */

    while(dataStructType != BUFFER && dataStructType != LINKED_LIST) /* while the user put in an invalid option */
    {
        printf("invalid input!\tplease try again.\n\n"); /* print error message to the user and return the process */
        printf("please insert the number of the data structure you want to use and press enter:\n1 - Buffer.\n2 - Linked List.\n");
        scanf("%d",&dataStructType);
    }

    if(dataStructType == BUFFER) /* if the user chose buffer as the data structure type */
    {
        printf("you have chosen option one - Buffer data structure type.\n");
        pointer = calloc(LINE_SIZE, sizeof(char));
        if(!pointer) /* if pointer is NULL */
        {
            printf("error!\t memory allocation failed.\t please try again later."); /* error message for the user */
            return 0; /* exit main function and the program */
        }else /* if the memory allocation succeeded */
        {
            readText(pointer,dataStructType); /* call readText function with BUFFER dataStructType */
            printText(pointer,dataStructType); /* call printText function with BUFFER dataStructType  */
        }
    }else /* if the user chose linked list as the data structure type */
    {
        printf("you have chosen option two - Linked List data structure type.\n");


        head = (struct Node*)calloc(1, sizeof(struct Node));

        if(!head) /* if head is NULL */
        {
            printf("error!\t memory allocation failed.\t please try again later."); /* error message for the user */
            return 0; /* exit main function and the program */
        }else /* if the memory allocation succeeded */
        {
            pointer = head;
            readText(pointer,dataStructType); /* call readText function with linkedList dataStructType */
            printText(pointer,dataStructType); /* call printText function with linkedList dataStructType  */
        }
    }
    if(dataStructType == BUFFER) /* if the data struct type is buffer */
        free(pointer); /* free the program memory */
    else /* if data struct type is linked list */
    {
        pointer = head; /* re-aim the pointer to the first Node */
        while(head->next != NULL) /* if we have more unfree memory that used by Nodes */
        {
            pointer = (head->next); /* set the pointer to the next Node */
            free(head); /* free the node that pointed by head */
            head = NULL; /* safety step */
            head = pointer; /* re-aim head to the node that was not freed yet */
        }
    }
    return 0;
} /* end of main function */

/* readText function.
 *
 * mission: read text from standard input and store it in a data structure by the following rules:
 *      if there is not enough memory the function will try to find new memory for the structure.
 *      if the function cant find memory she will store the text until the memory is full and print him.
 *
 * parameters:
 *      pointer - points to the start of the data structure.
 *      dataStructType - an integer that represent the data struct type.
 *
 * available data structures:
 *      1 - Buffer - Array.
 *      2 - linkedList - Linked List.
 */

void readText(void *pointer,int dataStructType)
{ /* start of readText function */
    register int cnt = 0; /* count the number of characters collected into the the array until the end of the specific line (limited for 60 characters for a line) */
    register int currentCell = 0; /* counter to count the collected characters **/
    char c; /* character variable to collect characters from the input */
    int lines = 1; /* lines counter */
    void *holder = NULL; /* temporary pointer to a new line */
    printf("please enter your text and in the end press cntrl+d\n");
    if(dataStructType == BUFFER) /* if the structure type is a buffer. */
    {
        while((c = getchar()) != EOF)
        {
            if (c != '\n') /* if the character is '\n' skip the character */
            {
                if (cnt == LINE_SIZE - 1) /* if this is the sixty character (starts from index 0) */
                {
                    cnt = 0; /* restart counter value */
                    lines++; /* add a "line" to calculate the memory size */
                    holder = realloc(pointer,  ((lines * LINE_SIZE) * sizeof (char))); /* reallocate new memory including memory for a new "line" */
                    if (holder == NULL) /* if the memory allocation failed */
                    {
                        printf("error!\t memory allocation failed.\n the program will now print the successfully collected text.\n"); /* message for the user */
                        printf("after printing the collected text the program will be finished\n"); /* message for the user */
                        printText(pointer, BUFFER); /* call printText function to print the collected text */
                    } else /* if the memory allocation succeeded */
                    {
                        pointer = holder; /* re-aim the pointer to the start of the new allocated memory */
                     } /* if we did not finished to collect text into a line and the character is not '\n' */
                (*(((char*)pointer) + currentCell)) = c; /* place the character in the current cell of the array */
                cnt++; /* increment counter by one */
                currentCell++; /* increment current cell counter by one */
            }
        } *(((char*)pointer) + currentCell) = c;  /* place the EOF character to sine the end of the array */
    }else /* if the structure type is a linked list. */
    {
        holder = pointer; /* save the address of the first Node */
        while((c = getchar()) != EOF)
        {
            if (c != '\n') /* if the character is '\n' skip the character */
            {
                if(cnt == LINE_SIZE - 1) /* if this is the sixty character (starts from index 0) */
                {
                    cnt = 0; /* restart counter value */
                    lines++; /* in this case adding a new Node to calculate the memory size */
                    (((struct Node *)pointer)->next) = (struct Node*) calloc(1,sizeof (struct Node)); /* allocate new memory for another new Node and point the "last" Node pointer to the new Node */
                    if ((((struct Node *)pointer)->next) == NULL) /* if the memory allocation failed */
                    {
                        printf("error!\t memory allocation failed.\n the program will now print the successfully collected text.\n"); /* message for the user */
                        printf("after printing the collected text the program will be finished\n"); /* message for the user */
                        printText(pointer, LINKED_LIST); /* call printText function to print the collected text */
                    } else /* if the memory allocation succeeded */
                    {
                        pointer = ((struct Node*)pointer)->next; /* re-aim the pointer to the new node that allocated */
                    }
                } /* if we did not finished to collect text into a line and the character is not '\n' */
                (((struct Node *) pointer)->data[cnt]) = c;  /* place the character in the current cell of the array */
                cnt++; /* increment counter by one */
            }
        } (((struct Node *) pointer)->data[cnt]) = c; /* place the EOF character to sine the end of the array */
        pointer = holder; /* re-aim the pointer to the first Node */
    }
} /* end of readText function */


/* printText function.
 *
 * mission: print the text that was collected by readText function to one of two data struct types:
 *      print until the end of the file (the end of the collected text).
 *      print sixty characters per a line.
 *
 * parameters:
 *      pointer - points to the start of the data structure.
 *      dataStructType - an integer that represent the data struct type.
 *
 * available data structures:
 *      1 - Buffer - Array.
 *      2 - linkedList - Linked List.
 */

void printText(void *pointer,int dataStructType)
{ /* start of printText function */
    register int cnt = 0; /* count the number of characters printed from a specific line (limited for 60 characters for a line) */
    register int currentCell = 0; /* counter to count the collected characters */

    if (dataStructType == BUFFER) /* if the data structure is buffer */
    {
        while (*(((char*)pointer) + currentCell) != EOF) /* while we still have characters to print */
        {
            if (cnt == LINE_SIZE - 1) /* if we printed 60 characters print an enter for a new line */
            {
                printf("\n"); /* print a new line */
                cnt = 0; /* restart the counter */
            } else /* if there is more characters to print until 60 characters */
            {
                putchar(*(((char*)pointer) + currentCell)); /* print the character */
                cnt++; /* count another character that was printed */
                currentCell++; /* increment current cell counter by one */
            }
        }
    } else /* else if the data structure is a linked list */
    {
        while((((struct Node*)pointer)->data[cnt]) != EOF) /* while we still have characters to print */
        {
            if (cnt == LINE_SIZE - 1) /* if we printed 60 characters print an enter for a new line */
            {
                printf("\n"); /* print a new line */
                cnt = 0; /* restart the counter */
                if(((struct Node*)pointer)->next == NULL) /* if there are no more Nodes in the linked list */
                    exit(EXIT_FAILURE); /* exit the program because we finished to print the text */
                else /* if there are more nodes in the linked list */
                    pointer = ((struct Node*)pointer)->next; /* set the pointer to the next Node */
            }else /* if there is more characters to print until 60 characters */
            {
                putchar(((struct Node*)pointer)->data[cnt]); /* print the character */
                cnt++; /* count another character that was printed */
            }
        }
    }
} /* end of printText function */





Thank to anyone that was trying to help, love that community

CrazyTux
  • 204
  • 2
  • 12
  • 1
    Your use of `void *pointer` when you mean `char *` isn't helpful and can often mask type issues preventing the compiler from doing normal type-checking for you. Limit the use of `void*` where you are actually handling two or more pointer types through a common pointer, and don't use it to mask what would otherwise by *Strict-Aliasing* violations. – David C. Rankin Jun 08 '21 at 18:32
  • 1
    Also, you haven't run your code through a memory error check program like `valgrind` yet, have you? You have bigger issues with your "buffer" implementation and your "linked list" misses freeing all memory allocated. – David C. Rankin Jun 08 '21 at 18:42
  • i dont know what valgrind is, kind of new to this stuff. – CrazyTux Jun 08 '21 at 18:47
  • 2
    `valgrind` is the Memory Use/Error Check for Linux, Windows has similar tools in VS, etc.. It tracks your use of allocated memory showing errors in your use of that memory like reading or writing outside the allocated block, basing a condition or check on an uninitialized area of that memory, or failing to free or attempting to free memory not allocated. You have invalid reads in your buffer implementation. Using valgrind is simple, just run your code through it, e.g. `valgrind ./yourprog` and it will do the rest. – David C. Rankin Jun 08 '21 at 18:51
  • 1
    See answer to [Creating an dynamic array, but getting segmentation fault as error](https://stackoverflow.com/a/67794158/3422102) for buffer and `valgrind` use and see [Singly Linked List of Strings With Sorted Insertion](https://pastebin.com/PechfyQa) for linked list use. (you don't need sorted insertion, so just rewrite an `add()` function adding a `tail` pointer for O(1) insertions, similar to [Singly Linked List of Integers](https://pastebin.com/R2AewR3A). – David C. Rankin Jun 08 '21 at 19:02