简体   繁体   中英

How to print array using pointer variable in plain C

I'm doing some tests with functions that return arrays and, with some reading, I came with this:

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

int i;

char * askData() {
    static char data[5];
    for(i = 0; i < 5; i++)
        scanf("%s", &data[i]);

    return data;
}

int main() {
    char* data = askData();
    
    printf("Flag 1\n");
    for(i = 0; i < 5; i++)
        printf("Loop %i: %s\n", i, &data[i]);

    printf("Flag 2\n");
}

What I want to do is to print each element from the pointer separately (much like an array, but I didn't used it because aparently a C function can't return an array).

Input:

Harry
Hermione
Ronald
Draco
Voldemort

Intended Output:

Flag 1
Loop 0: Harry
Loop 1: Hermione
Loop 2: Ronald
Loop 3: Draco
Loop 4: Voldemort
Flag 2

Current Output:

Flag 1
Loop 0: HHRDVoldemort
Loop 1: HRDVoldemort
Loop 2: RDVoldemort
Loop 3: DVoldemort
Loop 4: Voldemort
Flag 2

in printf("Loop %i: %s\n", i, %data[i]);

you are printing a char that's why %c is required and while printing % is not required

printf("Loop %i: %c\n", i, data[i]);
 #include <stdio.h>
   #include <stdlib.h>
   
   char * askData() {
       static char data[5];
       for(i = 0; i < 5; i++)
           scanf("%s", &data[i]);
   
       return data;
   }
   
   int main() {
       char* data = askData();
       int i; //its better here

       printf("Flag 1\n");
       for(i = 0; i < 5; i++)
           printf("Loop %i: %c\n", i, data[i]);
   
       printf("Flag 2\n");
   }

data is an array of char s, only capable of holding a single string that is 4 char s long. It is incorrect to loop through each char of data trying to store a string there. You should get rid of the loop in askData , and instead call that function in a loop, similar to below.

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

#define NUM_NAMES 5

// no point in making i global

char * askData() {
    // 5 chars can only hold a string of 4, not big enough for the names
    // you indicated. Memory is cheap, use some
    static char data[256];
    // limit scanf to read one less than the size of data, so as not to overflow
    scanf("%255s", data);

    return data;
}

int main(void) {
    printf("Flag 1\n");
    // better practice to use size_t types when working with sizes
    for(size_t i = 0; i < NUM_NAMES; i++){
        // call askData in a loop. Each call will overwrite the data there from the previous call
        char* data = askData();
        // %zu is the correct format specifier for printing size_t type
        printf("Loop %zu: %s\n", i, data);
    }

    printf("Flag 2\n");
}

Note, if you want to save each input rather than overwriting, you'll need a 2D array, something like data[NUM_NAMES][256]; , then you could call askData once and reinstate the loop in that function, or continue to call askData in a loop and pass in the string index as an argument.

Demonstration

So you're right C doesn't return arrays in the sense that you are talking about, however the way we do that in C is by utilizing two ideas together:

  1. Working with memory: By allocating a region of memory and then returning the starting location of that memory region.

    The function call to allocate memory is called malloc and then you have to use the free call to release that memory region.

  2. Pointer Arithmetic : I'm sure you already know that C has some basic types (char, int, long, float, double, and lately bool); each takes a different amount of memory and so C also provides the convenience of understanding typed pointers (pointers are variables that mark a memory location). A typed pointer understands how "big" it's associated type is in bytes and when you increment its value by 1 in C internally it's incremented by the size of the type.

Combining these ideas we can get arrays:

So for example if you have an array of five integers then you would allocate a region that is 5 * sizeof(int) ; Assuming a modern system the sizeof(int) is going to be 32-bits (or 4 bytes); so you will get a memory region of 20 bytes back and you can fill it up with the values.


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

int * get_numbers(size_t count) {

     int *data = malloc(count * sizeof(int));
     if (!data) {
         return NULL; // could not allocate memory
     }

     // notice that we are increasing the index i by 1
     // data[i] shifts properly in memory by 4 bytes
     // to store the value of the next input.

     for(int i=0; i < count; i++) {
           scanf("%d", &data[i]);
     }
}

int main() {
     int *data = get_numbers(5);
     if (data == NULL) {
          fprintf(stderr, "Could not allocate memory\n");
          exit(-1);
     }

     for(int i = 0; i < 5; i++) {
         printf("data[%d] = %d\n", i, data[i]);
     }

     free(data); 
}

Now in your case you have a bit of a complication (but not really) you want to be able to read in names, which are "strings" which don't really exist in C except as array of characters.

So to rephrase our problem is that want an array of names. Each name in itself is an array of characters. The thing is, C also understands type pointer pointers (yes a pointer to pointers) and can figure out the pointer arithmetic for that.

So we can have a memory region full of different types; the type pointers themselves can have a list of pointers in a memory region; and then make sure that each pointer in that list is pointing to a valid memory region itself.


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


char *get_one_name() {
    char *name = NULL;
    size_t len = 0;
    printf("Enter a name:");
    // getline takes a pointer, which if it's set to NULL
    // will perform a malloc internally that's big enough to
    // hold the input value.
    getline(&name, &len, stdin);
    return name;
}

char ** get_names(size_t count) {

    // this time we need memory region enough to hold
    // pointers to names
     char **data = malloc(count * sizeof(char *));
     if (!data) {
         return NULL; // could not allocate memory
     }

     for(int i=0; i < count; i++) {
         data[i] = get_one_name();
     }

     return data;
}

void free_names(char **data, size_t count) {
    for(int i = 0; i < count) {
        if(data[i] != NULL) {
            free(data[i]);
        }
    }
    free(data);
}

int main() {
     char **data = get_names(5);
     if (data == NULL) {
          fprintf(stderr, "Could not allocate memory\n");
          exit(-1);
     }

     for(int i = 0; i < 5; i++) {
         printf("data[%d] = %d\n", i, data[i]);
     }

     free_names(data, 5);
}

Hopefully this gives some ideas to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM