-2

how to receive strings from user to the empty string in c receive the string and put into an array and then print it.

int main() {
    int i=0;
    char st[LEN];
    char ch;

    while(st[0]!='\0') {
        i=0;
        printf("Enter name of student:");

        while(ch!='\n') {
            ch=getchar();
            st[i]=ch;
            i++;
        }
    }
}

snapshot

Roham Rafii
  • 2,929
  • 7
  • 35
  • 49
joo shane
  • 13
  • 3
  • int main() { int i=0; char st[LEN]; char ch; while(st[0]!='\0') { i=0; printf("Enter name of student:"); while(ch!='\n') { ch=getchar(); st[i]=ch; i++; } } } – joo shane Jun 07 '17 at 00:30
  • 1
    You need to iniialize "ch' and "st" before the "while" statements. – TonyB Jun 07 '17 at 01:31

3 Answers3

1

Alright, since I got called out, I will try to add a bit of meat around the bone. However, I will not simply hand you the code to do the task, it would spoil the fun.

The first part is to figure out how to gather the names entered by the user and store it in a variable. C does not handle String as a data type instead they are represented by an array of char (char[]) that ends with a null bytes, the character \00. There are many functions that allow you to take an input from a user : getchar, gets, fgets, scanf, etc. Here, you will need to do a bit of googling to figure out which one you should use for your particular case.

Afterwards, you want to figure out how to store the strings you collected into some sort of list. You would represent that as an array of strings. As we said, strings are not a thing in C. So you need to declare an array of array of char (char[][]). It is possible to grow the size dynamically as you add new items to the list with memory manipulation functions like malloc and realloc. But to start, I suggest that you stick to a fixed size array until you understand how it works.

The last step is to print the names you collected. Use a loop to iterate over your list of strings and print them one by one using the function printf.

Finally here's a pseudo code that boldly describes the process :

students: List of string
input: String
count: Integer

// Gather the names
while 1:
    print "Enter the name of a student : "
    input = readUserInput()

    if input is a null byte:
        break the loop
    else:
        students[count] = input
        increment count

// Print the names
for i in [0, count]:
    print students[i] + '\n' // '\n' represents a carriage return

Here are some random links that explain some of the concepts. Remember, google is your friend!

Which is the best way to get input from user in C?

https://www.tutorialspoint.com/cprogramming/c_arrays.htm

https://www.tutorialspoint.com/cprogramming/c_loops.htm

https://www.tutorialspoint.com/c_standard_library/c_function_printf.htm

user3220633
  • 414
  • 4
  • 13
  • 1
    When you post an answer to a question, you are expected to explain your answer *within* the body of the question. Referring to other sites as supporting your answer is not acceptable. There is no guarantee the links will even work 3 months from now. Take the time to explain your answer. If there are concise statements that will support your answer, then limited reference to offsite information is allowed for, e,g. linking to a particular section of the C11 Standard, etc. General links to use of specific functions, while it may help the OP, does not directly answer the question. – David C. Rankin Jun 07 '17 at 08:31
  • @DavidC.Rankin Aside from the question being extremely unclear and of practically zero value to the future users of SO, this is a question from the student doing his homework. The homework is meant to be done by him / her, not by SO community. Therefore, guidance provided in the answer IMO is appropriate. Besides that, more and more people nowadays think of SO as a free coding service, which happens only because many people pursuing SO reputation increase do provide this kind of service. – ZenJ Jun 07 '17 at 20:27
  • 1
    @ZenJ while I don't disagree with your sentiment, I am a bit confused how it applies to my comment about not providing an answer that consists solely of offsite links that may or may not be working tomorrow. Perhaps my comment is unclear, but an answer that contains nothing but links to "here is a link to a tutorial -- go learn..." without any explanation of what part of the question it applies to are not appropriate as an answer. The poster has more than 20 reputation and can provide referrals in a comment or if the question is unclear ask for further clarification. – David C. Rankin Jun 07 '17 at 20:34
  • Hello, I do agree that my answer was not really detailed, but so was the question. However, I did mention the different concept he needs to grasp to be able to formulate a relevant question. My feeling is that he doesn't have the vocabulary to do the google search. This being said, I did upvote your answer and apologize for being a bit cheeky! – user3220633 Jun 09 '17 at 09:05
1

You have a number of options available to you to take into consideration. First, since you are reading lines-of-input containing the names, using a line-oriented input function like fgets makes a lot of sense. Then you only have two considerations to check regarding end of input, (1) fgets returns NULL indicating EOF or (2), you check the first character of the buffer filled by fgets to see if it is the '\n' character (indicating that Enter alone has been pressed.

Next you need to consider what data structure you will use to hold the array of names until you have gathered all the input. You can use an array of struct as shown in the other answer, or you can simply use a *pointer-to-pointer-to-char` (a double-pointer) to allocate pointers, as needed, and assign the address for an allocated block of memory containing each name.

The procedure is straight forward. First allocate some reasonably anticipated number of pointers to work with. Read names, allocate storage for each, copy the name to the allocated memory and then assign the memory address to each pointer. When you reach the limit of your currently allocated pointers, simply realloc additional pointers and keep going.

Once all the names have been collected, you simply output the names (I have included the pointer index as well) and then free the memory of each name and then after all names are printed and freed, free the pointers and you are done. You can do something similar to the following:

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

enum { MAXP = 32, MAXC = 256 };  /* constants */ 

void *xcalloc (size_t nmemb, size_t size); /* helper functions */
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc);

int main (void) {

    size_t max = MAXP, n = 0;       /* initial ptrs and counter */
    char **a = xcalloc (max, sizeof *a);  /* mem for MAXP ptrs */ 

    for (;;) {                 /* loop until empty line or EOF */
        size_t len = 0;
        char buf[MAXC] = "";

        /* read into buf from stdin, check if empty */
        if (!fgets (buf, MAXC, stdin) || *buf == '\n')
            break;

        len = strlen (buf);     /* get length of buf */
        if (buf[len-1] == '\n') /* test for '\n' */
            buf[--len] = 0;     /* remove '\n' */

        a[n] = xcalloc (len + 1, 1);    /* mem to hold buf  */
        strcpy (a[n++], buf);           /* copy buf to a[n] */

        if (n + 1 == max) /* ptr limit reached, realloc ptr
                           * note: +1 insures a sentinel pointer
                           * with bits zeroed as the last pointer */
            a = xrealloc (a, sizeof *a, &max, MAXP);
    }

    for (size_t i = 0; i < n; i++) {    /* print and free mem */
        printf ("a[%3zd] : %s\n", i, a[i]);
        free (a[i]);   /* free memory allocated for each name */
    }
    free (a);  /* free pointers */

    return 0;
}

/* simple calloc with error-checking */
void *xcalloc (size_t nmemb, size_t size)
{
    void *memptr = calloc (nmemb, size);
    if (!memptr) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }

    return memptr;
}

/* simple realloc with error-checking */
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc)
{
    void *memptr = realloc ((char *)ptr, (*nelem + inc) * psz);
    if (!memptr) {
        fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }   /* zero new memory (optional) */
    memset ((char *)memptr + *nelem * psz, 0, inc * psz);
    *nelem += inc; /* update number of elements allocated */

    return memptr;
}

Above a static buffer of 256 characters was used to read each name from stdin. If for any reason that may not be enough, you can always validate a complete line was read by adding a check for the length and checking for the trailing '\n'.

Example Use/Output

$ ./bin/readprn <dat/namesfirst.txt
a[  0] : adam
a[  1] : allice
a[  2] : barny
a[  3] : beauregard
a[  4] : bell
a[  5] : benjamin
a[  6] : betty
a[  7] : bill
a[  8] : buck
a[  9] : buddy
a[ 10] : candice
a[ 11] : caset
a[ 12] : cathy
a[ 13] : charles
a[ 14] : chris
a[ 15] : chuck
a[ 16] : clark
a[ 17] : david
a[ 18] : don
a[ 19] : eli
a[ 20] : elizabeth
a[ 21] : emma
a[ 22] : eric
a[ 23] : ester
a[ 24] : frank

The code behaves the same if you manually type each name and then press Enter alone on the final line. (I just happened to have a names file)

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/readprn <dat/namesfirst.txt
==28428== Memcheck, a memory error detector
==28428== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28428== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28428== Command: ./bin/readprn
==28428==
a[  0] : adam
<snip>
a[ 24] : frank
==28428==
==28428== HEAP SUMMARY:
==28428==     in use at exit: 0 bytes in 0 blocks
==28428==   total heap usage: 26 allocs, 26 frees, 413 bytes allocated
==28428==
==28428== All heap blocks were freed -- no leaks are possible
==28428==
==28428== For counts of detected and suppressed errors, rerun with: -v
==28428== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • side notes: 1) --> `if (n == max) /* ptr limit reached, realloc ptr */` 2) If `realloc` fails Memory release is not explicitly done. – BLUEPIXY Jun 07 '17 at 10:48
  • Note (1) that when reserved as `NULL`, all bits 0 and `NULL` are not necessarily the same. – BLUEPIXY Jun 07 '17 at 10:54
  • `if (n + 1 == max)` intentionally provides for a *sentinel NULL* as the last element for use in iterating. Your note on all bits 0 and NULL is well taken, though for gcc they are for practical purposes equivalent (`(void *)0`), there may be other compilers that treat them differently. If `realloc` fails, the program exits, and you are correct there is no explicit release before calling `exit` as the memory is released on `exit`. – David C. Rankin Jun 07 '17 at 20:03
  • I thought that is probably the intent, but I noted it. You better add comments to the code to clarify your intentions. – BLUEPIXY Jun 07 '17 at 20:13
  • Yes, that was a good catch. It just provides the option of iterating over the pointers for the cost of an additional pointer. I'll drop a comment. – David C. Rankin Jun 07 '17 at 20:14
0

sample code

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

#define LEN 32

typedef struct student {
    char *name;
} Student;

void atEnd(Student *s, int n, const char *message, int exit_code){
    for(int i = 0; i < n; ++i){
        free(s[i].name);
    }
    free(s);
    fputs(message, stderr);
    exit(exit_code);
}

int main(void) {
    Student *students = NULL;
    int n = 0;//number of students

    while(true){
        char st[LEN];
        int i, ch;

        printf("Enter name of student:");

        for(i = 0; (ch = getchar())!= EOF && ch != '\n' && i < LEN-1; ++i){
            st[i]=ch;
        }
        if(i == 0)
            break;
        else if(i == LEN-1 && ch != '\n'){
            char *mes =
                "Your name is longer than the programmer assumes.\n"
                "Please tell the programmer to change the program.\n"
            ;
            atEnd(students, n, mes, EXIT_FAILURE);
        }
        st[i] = 0;
        Student *temp = realloc(students, (n+1)*sizeof(*students));
        if(!temp){
            atEnd(students, n, "realloc failed.\n", EXIT_FAILURE);
        }
        students = temp;
        if(NULL == (students[n++].name = malloc(strlen(st)+1))){
            atEnd(students, n, "malloc failed.\n", EXIT_FAILURE);
        }
        strcpy(students[n-1].name, st);
    }

    for(int i = 0; i < n; ++i){
        puts(students[i].name);
    }
    atEnd(students, n, "", EXIT_SUCCESS);
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70