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?
CodePudding user response:
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
}
}
CodePudding user response:
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);
CodePudding user response:
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.