2

I have written this program that asks the user for a name and then prints the name. Here are the steps in detail:

  • asks the user for the number of characters the name (i.e. sentence) will have. It includes empty spaces and the terminator character \0, then stores it;
  • it creates a block of memory with num_char addresses, and stores the address of the first item in ptr;
  • within the else section, an array of unknown size is declared, which will be used to store the name and its first address is assigned to ptr;
  • then the array is assigned with size num_char;

Here's the code:

#include <stdio.h>
#include <stdlib.h>
//an attempt at a program that asks for a name, stores it in an array and then prints it

int main() {
    int num_char;
    char *ptr;

    printf("input number of characters of your name (spaces and terminator character included): ");

    scanf("%d", &num_char);

    ptr = char *malloc(num_char * sizeof(char)); //creates a block of mem to store the input name, with the same size, and then returns the adress of the beginning of the block to ptr

    if (ptr == NULL) {
        printf("allocation not possible");
    } else {
        ptr = char name[]; //ptr stores the adress of the first char in string

        char name[num_char], //declaration of an array with num_char elements

        printf("input name: ");

        scanf("%s", name);
        printf("input name was: %s", name);
    }
    return 0;
} 

However I get three compilation errors which are:

  • "expected expression before 'char' " at ptr = char *malloc(num_char * sizeof(char) ); and ptr = char name[];
  • "expected declaration specifiers or '...' before string constant" at printf("input name: ");

I am a college student just beginning at C and programming in general so a detailed explanation of any error of any kind and how to fix it would be very much appreciated :)

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • `ptr = char *malloc(num_char * sizeof(char) )` Just remove the `char *`. If you are trying to do a cast then it needs to be `(char *)` but a cast is not needed in C. – kaylum Mar 08 '21 at 21:04
  • `char name[num_char],` -> `char name[num_char];` – kaylum Mar 08 '21 at 21:04
  • `ptr = char *malloc(num_char * sizeof(char));` should be `ptr = malloc(num_char);` You [shouldn't cast the result of malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc), and `sizeof(char)` is 1 by definition so there's no point in multiplying by `sizeof(char)`. – user3386109 Mar 08 '21 at 21:04
  • 1
    @chqrlie `ptr = char name[];` – anastaciu Mar 08 '21 at 21:26
  • This is a weird assignent, so you allocate memory for `ptr` and then you must assign an array to `ptr`? That's a memory leak right there. – anastaciu Mar 08 '21 at 21:46
  • It would be a good idea to learn from a book or other resource that shows you how the language works; it seems you're just guessing the syntax which is not going to end well – M.M Mar 08 '21 at 21:48

2 Answers2

1

These are syntax errors because:

  • ptr = char *malloc(num_char * sizeof(char)); should have been ptr = (char *)malloc(num_char * sizeof(char)); or simply ptr = malloc(num_char * sizeof(char));.

  • ptr = char name[]; is meaningless. You do not need to change ptr at all.

  • char name[num_char], is a C99 variable length array definition, but with a trailing , so the next line is expected to have another definition, hence the second error.

You must choose to either allocate memory from the heap with malloc() or define an array as a local variable.

Here is a modified version:

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

int main() {
    int num_char;
    char *ptr;

    printf("input number of characters of your name (spaces and terminator character included): ");

    if (scanf("%d", &num_char) != 1 || num_char <= 1) {
        printf("invalid input\n");
        return 1;
    }
    /* discard the rest of the input including the newline */
    int c;
    while ((c = getchar()) != EOF && c != '\n')
        continue;

    //allocate a block of memory to store the name
    ptr = malloc(num_char * sizeof(char));

    if (ptr == NULL) {
        printf("allocation not possible");
    } else {
        printf("input name: ");

        if (scanf("%[^\n]", ptr) == 1)
            printf("input name was: %s\n", name);
        else
            printf("no input was given\n");

        free(ptr);
    }
    return 0;
} 

Also note that scanf() may read more than num_char bytes if the input has more non white bytes, so it would be much safer, but non-trivial to given scanf() the information about the array size:

    if (ptr != NULL) {
        char format[32];
        snprintf(format, sizeof format, "%%%d[^\n]", num_char - 1);
        printf("input name: ");
        if (scanf(format, ptr) == 1) {
            printf("input name was: %s\n", name);
            // should discard the rest of the line and the newline
        } else {
            printf("no input was given\n");
        }
    }
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

As I stated in the comments, this is a wierd set of requirements for, what I assume is an assignment, here is more or less what you should do, with comments:

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

void clear_buffer()
{ // routine to clear standard input
    int c;
    while ((c = getchar()) != '\n' && c != EOF){}
    if (c == EOF)
    {
        exit(EXIT_FAILURE);
    }
}
int main()
{
    int num_char;
    char *ptr;

    printf("input number of characters of your name (spaces and terminator character included): ");
    // less than 9 + 1 null byte characters for the name not allowed
    while (scanf("%d", &num_char) != 1 || num_char < 10)
    { 
        printf("Bad input, try again: ");
        clear_buffer();
    }
    ptr = malloc(num_char); // removed char*, you may wanted a cast, 
                            // but even that is unneeded,
                            // The size of char is always 1 byte
                            // I still don't understand why this is asked, but well...
    if (ptr == NULL)
    {
        perror("allocation not possible"); // perror prints the apropriate error
    }
    else
    {
        char name[num_char]; // declaration of an array with num_char elements
        free(ptr);           // to make ptr point to another memory location, it must be freed
        ptr = name;          // ptr now points to the first element of the name array

        clear_buffer();
        printf("What's the name ? ");
        // read name with spaces from standard input
        if (fgets(name, num_char, stdin))
        {                   
            name[strcspn(name, "\n")] = '\0'; // remove \n 
            printf("input name was: %s", ptr); // print name through ptr 
        }  
        else
        {
            puts("Bad input");
        }                    
       
    }
    return EXIT_SUCCESS;
}

Pending on ambiguous interpretation...

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • `while ((c = getchar()) != '\n' && c != EOF){}` is needed in all cases, otherwise `fgets()` will just read the rest of the first line of input... and the newline will be left pending is the name has exactly `num_char-1` characters. Also infinite loop on unexpected end of file reading `num_char`. – chqrlie Mar 08 '21 at 22:11
  • Well... you have undefined behavior if `fgets(name, num_char, stdin)` returns `NULL`, but I am well past bedtime too :) – chqrlie Mar 08 '21 at 23:28
  • 1
    @chqrlie, indeed, I did broke the unspoken rule of mixing `scanf` with `fgets`, anyway any of these answers is too bullet proof, the teacher will want to know who did this :) – anastaciu Mar 09 '21 at 08:46