1

I want to fill an array of char pointers in the following format:

[name, number of email addresses, all the email addresses]*number of people. The number of mail adresses for each person isn't known at first.

  • I have to use char *contacts[N]
  • When printing the array it only prints contacts[0], so I guess my way of scanning the input is wrong

This is my main so far:

int main()
{
    char *contacts[N];
    int nextAvailable = 0;
    int * const nextAvailableP = &nextAvailable;
    add(contacts, nextAvailableP);
    //Printing this way will only print contacts[0]
    int i;
    for (i = 0; i < nextAvailable; i++) {
        printf("%s", contacts[i]);
    }
}

This is the add function:

int add(char *contacts[], int *nextAvailableP) {
    if (*nextAvailableP > 97) {
        printf("Not enough memory\n");
        return FALSE;
    }

    char tempName[50];
    char tempMail[50];
    int numberOfMails = 1;

    printf("Enter your name\n");
    fgets(tempName, 50, stdin);
    if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
        tempName[strlen(tempName) - 1] = '\0';

    contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));

    if (contacts[*nextAvailableP] == NULL) {
        printf("Not enough memory\n");
        return FALSE;
    } else {
        strcpy(contacts[*nextAvailableP], tempName);
    }

    (*nextAvailableP)++;
    int numberOfMailsIndex = *nextAvailableP;
    itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
    (*nextAvailableP)++;
    

    printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
    fgets(tempMail, 50, stdin);

    while (strcmp(tempMail, "-1") != 0) {
        if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
            tempMail[strlen(tempMail) - 1] = '\0';
        }

        contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
        
        if (contacts[*nextAvailableP] == NULL) {
            printf("Not enough memory");
            return FALSE;
        } else {
            strcpy(contacts[*nextAvailableP], tempMail);
        }
        (*nextAvailableP)++;
        numberOfMails++;
        itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
        fgets(tempMail, 50, stdin);
    }
}

I thought I was initializing each cell in contacts to the requested size and then copying the word I scan from the user into it - but obviously I'm not. Should I iterate through each memory I've allocated char by char?

Btw, I know that the casting to *char isn't necessary

6
  • 1
    Don't ever use gets(). It's a dangerous function and has been removed from the language. Use fgets() instead. Commented Nov 23, 2020 at 8:36
  • What is this: contacts[*nextAvailableP] = numberOfMails;? contacts is an array of strings, you can't put numberOfMails in there. Commented Nov 23, 2020 at 8:38
  • You should be using an array of structs. Each struct can contain the name, number of emails, and a pointer to an array of emails. Commented Nov 23, 2020 at 8:39
  • 1
    @Barmar I have to use char *contacts[N] as part of the question. For the contacts[*nextAvailableP] = numberOfMails, I'll cast, thanks Commented Nov 23, 2020 at 8:41
  • @RedYoel you actually didn't mention what error exactly are you getting. Is it not getting the input? Is it malformed output, Or nothing is happening at all? Commented Nov 23, 2020 at 10:39

2 Answers 2

1

So this would be your corrected code

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

#define MAX_ENTRIES 50

int add(char *contacts[], int *nextAvailable);

int main(void){
    int i;
    char *contacts[MAX_ENTRIES];
    int nextAvailable = 0;
    add(contacts, &nextAvailable);
    add(contacts, &nextAvailable);

    for(i=0; i < nextAvailable ; i++){
        printf("%s\n", contacts[i]);
    }
}

char* intToString(int val, int base){
    //source: www.strudel.org.uk/itoa/
    static char buf[32] = {0};

    int i = 30;

    for(; val && i ; --i, val /= base)

        buf[i] = "0123456789abcdef"[val % base];

    return &buf[i+1];

}

int add(char *contacts[], int *nextAvailableP) {
    if (*nextAvailableP > 97) {
        printf("Not enough memory\n");
        return 0;
    }

    char tempName[50];
    char tempMail[50];
    int numberOfMails = 1;

    printf("Enter your name\n");
    fgets(tempName, 50, stdin);
    if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
        tempName[strlen(tempName) - 1] = '\0';

    contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));

    if (contacts[*nextAvailableP] == NULL) {
        printf("Not enough memory\n");
        return 0;
    } else {
        strcpy(contacts[*nextAvailableP], tempName);
    }

    (*nextAvailableP)++;
    int numberOfMailsIndex = (*nextAvailableP);
    contacts[numberOfMailsIndex] = malloc(5);
    (*nextAvailableP)++;

    printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
    fgets(tempMail, 50, stdin);

    while (strcmp(tempMail, "-1\n") != 0) {
        if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
            tempMail[strlen(tempMail) - 1] = '\0';
        }

        contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));

        if (contacts[*nextAvailableP] == NULL) {
            printf("Not enough memory");
            return 0;
        } else {
            strcpy(contacts[*nextAvailableP], tempMail);
        }
        (*nextAvailableP)++;
        numberOfMails++;
        fgets(tempMail, 50, stdin);
    }
    strcpy(contacts[numberOfMailsIndex], intToString(numberOfMails - 1,10));

}
Sign up to request clarification or add additional context in comments.

3 Comments

contacts[numberOfMailsIndex] = malloc(5); was the line I was missing, thank you! I allocted 1 byte for it, is it ok too?
One byte won't be enough. Remind that one caracter is one byte. if you have 10 email addresses you have '1' '0' '\0'. So 3 bytes.
@RedYoel If you are directly writing an 8-bit integer, you only need 1 byte to store upto 255. But if you are converting it to ASCII, you cannot store anything in 1 byte.
0

Your function add could be cut in a subfunction which gets a string from the user. This string will be stored in a allocated memory space which has the size of string.

Keep in mind : It's not a good practice to mix data of different nature in one array (names and email). It would be better to use structs (as @Barmar said).

I would do following steps:

  • Get name from user (char *)
  • Allocate memory and copy the name into it.
  • insert the pointer to this allocated memory into your array (contacts)
  • Get a email address put it in a dynamic allocated memory space
  • add its pointer to your array (Contacts
  • Increment emails counter
  • repeat
  • -1 detected
  • convert your email counter to string and the pointer into your array

Anyway here's a code that you can start play with:

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

#define MAX_ENTRIES 50
#define BUFFERSIZE 50

int add(char *contacts[], int *nextAvailable);
char *getString(char *queryText);
char* intToString(int val, int base);

int main(void){
    int i;
    char *contacts[MAX_ENTRIES];
    int nextAvailable = 0;
    add(contacts, &nextAvailable);
    add(contacts, &nextAvailable);

    for(i=0; i < nextAvailable ; i++){
        printf("%s", contacts[i]);
    }
}

int add(char *contacts[], int *nextAvailable){
    if(*nextAvailable > MAX_ENTRIES - 1){
        printf("Not enough memory\n");
        return 1;
    }

    contacts[*nextAvailable] = getString("Enter your name\n");
    if(contacts[*nextAvailable] == NULL){
        printf("Malloc Error\n");
        return 1;
    }
    ++(*nextAvailable);
    int counterfield = *nextAvailable;
    ++(*nextAvailable);
    int emailCounter = 0;
    while(1){

        if(*nextAvailable > MAX_ENTRIES - 1){
            printf("Not enough memory\n");
            return 1;
        }
        char *email = getString("Enter email\n");
        if(strcmp(email, "-1\n") == 0){

            contacts[counterfield] = malloc(5);
            contacts[counterfield] = intToString(emailCounter,  10);

            return 0;
        }
        emailCounter++;
        contacts[*nextAvailable] = email;
        ++(*nextAvailable);

    }


}


char *getString(char *queryText){
    char buffer[BUFFERSIZE];
    char *ret;
    printf("%s", queryText);

    fgets(buffer, BUFFERSIZE, stdin);
    ret = malloc(strlen(buffer));

    strcpy(ret, buffer);
    return ret;
}

char* intToString(int val, int base){
    //source: www.strudel.org.uk/itoa/
    static char buf[32] = {0};

    int i = 30;

    for(; val && i ; --i, val /= base)

        buf[i] = "0123456789abcdef"[val % base];

    return &buf[i+1];

}

7 Comments

Thanks, I'll consider that, but I would like to know what's wrong with my code. I tried to use ITOA, nothing changed
contacts[numberOfMailsIndex] = (numberOfMails + '0'); that is wrong. contacts is an array of pointers. so (numberOfMails + '0') will be a pointer. so if numberOfMails is 5 then you got a pointer pointing to 0x5+0x30 (0x35) . Thats not a valid adress pointing to a string. You need to do a malloc and do a int to string
Another error is that you compare your input to "-1". but fget gets the \n too. so try to compare with "-1\n" like while (strcmp(tempMail, "-1\n") != 0) {
I'm actually "cleaning" the '\0'. The while stops when entering "-1". As said, ITOA did no diffrence. I've tried itoa(numberOfMails, &contacts[*nextAvailableP], 10)
You compare the "-1" before your "cleaning". I don't undestand how you're able to exit your loop. Did you allocated the string you passed to itoa? The second parameter must be a pointer to a allocated memory space. Check out the other response i posted with your corrected code
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.