The issue is that you are not allocating any space for those names. You need to initialize each element in the array if you intend to use it with scanf.
char* names[6];
for( int i = 0; i < 6; ++i )
names[i] = malloc( 256 * sizeof *names[i] ); // or some other max value
scanf( "%s", names[1] );
Otherwise those pointers will be pointing anywhere in your memory, and attempting to read/write those locations will eventually result in a segmentation fault.
Answer from K-ballo on Stack Overflowc - array of pointers to strings - Stack Overflow
Pointer to string array in C - Stack Overflow
Why can you have an pointer to array of strings in C - Stack Overflow
How do I create (and use) an array of pointers to an array of strings in C? - Stack Overflow
So i am learning command lines arguments and just came cross char *argv[]. What does this actually do, I understand that this makes every element in the array a pointer to char, but i can't get around as to how all of this is happening. How does it treat every other element as another string? How come because essentialy as of my understanding rn, a simple char would treat as a single contiguous block of memory, how come turning this pointer to another pointer of char point to individual elements of string?
The issue is that you are not allocating any space for those names. You need to initialize each element in the array if you intend to use it with scanf.
char* names[6];
for( int i = 0; i < 6; ++i )
names[i] = malloc( 256 * sizeof *names[i] ); // or some other max value
scanf( "%s", names[1] );
Otherwise those pointers will be pointing anywhere in your memory, and attempting to read/write those locations will eventually result in a segmentation fault.
In your code names is an array of 6 pointers to char. Now each of these pointers can store the starting point (the address of the first character) of a new string. This means you can store the starting addresses of 6 different strings in your names variable.
But when you use a loop to initialize each of these strings, you need to inform the machine HOW long each string might be, so that it can allocate a continuous block of addresses whose first address can then be stored in your pointer to refer to your string. Thus, you must allocate a certain size you think should be sufficient to store your string (eg: 256 bytes, 1 byte being 1 character). In the absence of this, the machine doesn't know where to store all the bytes of your string and throws a segmentation fault due to illegal memory access.
Thus to do this, each of your 6 pointers must be allocated some space to store a string. This will be done in your loop using malloc(). Based on @K-ballo's code:
char* names[6];
int max_length = 256; // The maximum length you expect
for( int i = 0; i < 6; ++i )
names[i] = malloc( max_length * sizeof(char) ); // allocates max_length number of bytes
scanf( "%s", names[1] );
So now you basically have a 6 different blocks of max_length continuous char addresses that are each referred to by names[i]. When you do the scanf() it reads the bytes from standard input and puts then into these allocated bytes in memory referred to by names[1].
I had a difficult time at the start understanding all this, so just thought an elaborate explanation would help. :)
There are two way of working with array of characters (strings) in C. They are as follows:
char a[ROW][COL];
char *b[ROW];
Pictorial representation is available as an inline comment in the code.
Based on how you want to represent the array of characters (strings), you can define pointer to that as follows
char (*ptr1)[COL] = a;
char **ptr2 = b;
They are fundamentally different types (in a subtle way) and so the pointers to them is also slightly different.
The following example demonstrates the different ways of working with strings in C and I hope it helps you in better understanding of array of characters (strings) in C.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ROW 5
#define COL 10
int main(void)
{
int i, j;
char a[ROW][COL] = {"string1", "string2", "string3", "string4", "string5"};
char *b[ROW];
/*
a[][]
0 1 2 3 4 5 6 7 8 9
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 1 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 2 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 3 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 4 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 5 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
*/
/* Now, lets work on b */
for (i=0 ; i<5; i++) {
if ((b[i] = malloc(sizeof(char) * COL)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
}
strcpy(b[0], "string1");
strcpy(b[1], "string2");
strcpy(b[2], "string3");
strcpy(b[3], "string4");
strcpy(b[4], "string5");
/*
b[] 0 1 2 3 4 5 6 7 8 9
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 1 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 2 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 3 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 4 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 5 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
*/
char (*ptr1)[COL] = a;
printf("Contents of first array \n");
for (i=0; i<ROW; i++)
printf("%s \n", *ptr1++);
char **ptr2 = b;
printf("Contents of second array \n");
for (i=0; i<ROW; i++)
printf("%s \n", ptr2[i]);
/* b should be free'd */
for (i=0 ; i<5; i++)
free(b[i]);
return 0;
}
What would be the correct way to solve this problem?
Well, the correct way would be to use a library specifically designed for dealing with multilanguage interfaces - for instance gettext.
Another way, though patchier, would be to use a hash table (also known as "dictionary" or "hash map" or "associative map" in other languages/technologies): Looking for a good hash table implementation in C
It's probably not the answer you were looking for, but you've asked the wrong question to the right problem.
Here
char *names [] = {"hello", "Jordan"};
names is array of char pointers i.e it can holds pointers i.e names each elements itself is one char array. But here
char names [] = {"hello", "Jordan"};
names is just a char array i.e it can hold only single char array like "hello" not multiple.
In second case like
int main(void) {
char names[] = {"hello", "Jordan"};
return 0;
}
when you compile(Suggest you to compile with -Wall -pedantic -Wstrict-prototypes -Werror flags), compiler clearly says
error: excess elements in char array initializer
which means you can't have more than one char array in this case. Correct one is
char names[] = {'h','e','l','l','o','\0'}; /* here names is array of characters */
Edit :- Also there is more possibility if syntax of names looks like below
char names[] = { "hello" "Jordan" }; /* its a valid one */
then here both hello and Jordan gets joined & it becomes single char array helloJordan.
char names[] = { "helloJordan" };
The first is an array of pointers to char. The second is an array of char and would have to look like char names[] = {'a', 'b', 'c'}
from cdecl:
declare foo as array of pointer to array 2 of pointer to char
char *(*foo[])[2];
So, foo[0] is a pointer to array 2 of char *
That is the array, but for your use, you want:
declare foo as pointer to array 2 of pointer to char;
char *(*foo)[2];
Now you can do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *(*foo)[2];
printf("How many people?\n");
int n; scanf("%d", &n);
foo = malloc(sizeof *foo * n);
for (int i = 0; i < n; i++) {
char bufFirstName[1024];
char bufLastName[1024];
printf("Please insert the #%d first and last name:\n", i+1);
scanf("%s %s", bufFirstName, bufLastName);
char *firstName = malloc(strlen(bufFirstName) + 1);
char *lastName = malloc(strlen(bufLastName) + 1);
strcpy(firstName, bufFirstName);
strcpy(lastName, bufLastName);
foo[i][0] = firstName;
foo[i][1] = lastName;
}
for (int i = 0; i < n; i++) {
printf("Name: %s LastName: %s\n", foo[i][0], foo[i][1]);
}
return 0;
}
Compile with -std=c99
Note that using scanf, strcpy, strlen like that is unsafe because there can be a buffer overflow.
Also, remember to free your malloc's!
Not that your approach is wrong, but have you considered instead using a struct that includes first and last name, and then malloc'ing based on the number of names the user will enter:
typedef struct {
char* first;
char* last;
} person;
person* people = malloc(num * sizeof(*person));
This just simplifies pointer interaction. While the way you are doing it is a good exercise in understanding pointers better, it may not be the easiest way to understand.
If you are unable to use structs, you should instead be doing:
char** people;
people = malloc(2*num*sizeof(char*));
for (int i = 0; i < 2*num; i++)
people[i] = malloc(MAX_NAME_SIZE*sizeof(char));
Now you would need to reference the i th person via:
first name: people[i*2 + 0]
last name: people[i*2 + 1]
Make sure you reserve room for the characters of the strings:
char p[5][128];
and also make sure you limit the length when reading, so scanf() doesn't write outside the buffer:
if(scanf("%127s", p[i]) == 1)
{
p[i][127] = '\0'; /* Make sure it's terminated. */
}
First of all, the int array definition is wrong in your first test. it should be
int p[5];
Second you have to allocate memory for each pointer in your array. each element in your array char *p[5]; is a pointer.
You can use directly by scanf
char *p[5];
for(i=0;i<=4;i++)
{
scanf("%ms\n",&p[i]);
}
But this is not portable is available only for gcc>gcc2.7
or you have to allocate memory each time before scanf()
char *p[5];
for(i=0;i<=4;i++)
{
p[i]=calloc(100,1);
scanf("%99s\n",p[i]);
}