0

I'm having a really hard time trying something super simple in other languages. But in C I was given an exercise that says:

Write a function that receives an array of strings and modify it based on user input.

My code so far:

#include <stdio.h>
#define GEN 3
void fillGenes(char **);

int main() {
    char *genes[GEN] = {"Gen0", "Gen1", "Gen2"};
    
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
    }
    fillGenes(genes);
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
    }
    return 0;
}

void fillGenes(char **genes) {
    printf("Introduce the name of %d genes.\n", GEN);
    for(int i = 0; i < GEN; i++) {
        printf ("Name of gene %d\n", i);
        char newVal[10];
        scanf("%s", newVal);
        genes[i] = newVal;
    }
}

This is wrong, as stated by @Eugene Sh:
newVal is array local to the function, after the function is returned, genes will be an array of dangling pointer:

genes[i] = newVal;

The thing is that I cannot strcpy as it is invalid. How can I make this thing to work?

6
  • 2
    newVal is an array local to the function (actually, even worse - to the block that is inside the for loop). Once the function is returned, your genes will contain an array of dangling pointers. Commented Jan 10, 2023 at 15:11
  • @EugeneSh. Oh yes, that's the point. But I cannot perform a strcpy. Let me rephrase the question, I would like to solve this. Commented Jan 10, 2023 at 15:17
  • 2
    You can't strcpy because the array genes is initially containing pointers to string literals which cannot be written to. So you either define it as something like char genes[GEN][MAX_LEN]; to be able to overwrite the strings, or use dynamic allocation to overwrite the pointers. Commented Jan 10, 2023 at 15:20
  • 2
    char *genes[GEN] = {"Gen0", "Gen1", "Gen2"}; is not a modifiable array of strings. genes[i] = newVal; This is not how string assignment works. Also you cannot point at local arrays and return a pointer to one from a function. All of these issues are best studied by reading a good C programming book. Commented Jan 10, 2023 at 15:29
  • You are not supposed to modify the initial question with the solution. It is invalidating the answers and comments. Rolling back the edits.. Commented Jan 10, 2023 at 15:56

3 Answers 3

2

Problems:

  • Pointers at string literals do not point at modifiable memory, they are read-only.
  • You cannot return a pointer to a local array from a function.
  • You need to copy strings using strcpy or equivalent.

The easiest way to salvage the existing code might be to use the strdup function, which is essentially a combination of malloc + strcpy.

(strdup is at the time this is written not yet standard C, but will be later this year in the upcoming C23 release. For now you should be able to find it in string.h unless you compile with strict compiler settings.)

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

#define GEN 3
void fillGenes(char **);

int main() {
    char *genes[GEN] = // assign the pointers to read/writeable dynamic memory:
    { 
      strdup("Gen0"), 
      strdup("Gen1"), 
      strdup("Gen2")
    }; 
    
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
    }
    fillGenes(genes);
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
       free(genes[i]); // clean up when done using the data
    }
    return 0;
}

void fillGenes(char **genes) {
    printf("Introduce the name of %d genes.\n", GEN);
    for(int i = 0; i < GEN; i++) {
        printf ("Name of gene %d\n", i);
        char newVal[10];
        scanf("%s", newVal);

        free(genes[i]); // clean up not to create a memory leak
        genes[i] = strdup(newVal); // create a new read/writeable copy of the local string
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

"Pointers at string literals do not point at modifiable memory, they are read-only." --> more like "Modifying a string literal is UB.". Attempting to modify a string literal might work - its UB.
scanf("%s", newVal); too much like gets(). Suggest scanf("%9s", newVal);
1

You could accomplish this by editing a few parts of your code.

void fillGenes(char *genes[GEN][10])

The [] and * operator have precedence over the (), so it means the pointer to an array of 10 char. Change it to this:

void fillGenes(char (*genes)[10])

And this:

fillGenes(&genes);

to this:

fillGenes(genes); 

remove the & since it's already an array.

I would also recommend switching out scanf with fgets

You could accomplish that by removing this:

scanf("%s", genes[i]);

and adding this:

fgets(genes[i], 10, stdin);

Comments

0

There are a few ways to accomplish this. One of the ways is this:

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

#define GEN 3
void fillGenes(char **);
void fillGenes(char **genes) {
    printf("Introduce the name of %d genes.\n", GEN);
    for(int i = 0; i < GEN; i++) {
        printf ("Name of gene %d\n", i);
        char newVal[10];
        scanf("%s", newVal);
        genes[i]=calloc(100, 1);
        strcpy(genes[i], newVal); 
    }
}
int main() {
    char *genes[GEN] = {"Gen0", "Gen1", "Gen2"};
    
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
    }
    fillGenes(genes);
    for (int i = 0; i < 3; i++) {
       printf("%s\n", genes[i]);
    }
    return 0;
}

By allocating memory and copying the contents of newVal to your array, you avoid making the mistake of having your pointers all point to newVal instead.

Comments

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.