Dynamic array of strings / dynamic dictionary - c

beginner here
This is absolutely infuriating me, how do I create an array that holds strings where the length / amount of strings are unknown? I essentially want to create a dictionary where
array[0] = "word"
array[1] = "word2"
array[2] = "word3"
and so on
I tried :
array** = malloc(INIT); where init was defined as 10
memset(array, '\0', 10)
then, under a loop
array[i] = malloc(INIT)
array[i] = string from another source ( array2[i] ) (array2 is a char*)
but that just gives errors / junk text and I have no clue how to assign strings to the array
I'm having a hard time understanding pointers / jargon in general, I've looked at all the similar questions and can't understand any of the answers.

Try doing this -
int main(){
int i;
char *arr[10];
for(i=0;i<10;i++){
char str[1000];
scanf("%s", str);
arr[0] = (char*) malloc(strlen(str));
strcpy(arr[0], str);
}
return 0;
}

You can dynamically create an array of pointers to strings and in that way keep it flexible:
char** array = malloc(sizeof(char*)*n); // allocates an array of char* pointers
if you later need to extend the array use realloc
char** newarray = realloc(array,sizeof(char*)*(n+1));
if (newarray != NULL)
{
array = newarray;
...
}
You must also remember to allocate space for where the pointers point to for storing your strings
array[i] = strdup("blabla");
or
array[i] = malloc(strlen("blabla")+1);
strcpy(array[i], "blabla" );

Related

can't access some elements in malloc generated 2D array

I'm trying to make a 2D array in C with malloc for "hash map" project but as usual. something happend !
basically I have an issue of accessing the 3rd element of the 1st array arr[0][3], it's super weird (at least to me) ,so let me show you the code
1- create 2D array:
int main(void){
char*** table;
table = malloc(sizeof(char*) * 10);
//create array inside table
table[0] = malloc(sizeof(char) * 20);
return 0;
}
2- assign some strings to 1st array table[0]:
table[0][1] = "test1";
table[0][2] = "test2";
table[0][3] = "test3";
table[0][4] = "test4";
...
table[0][n] = "testn";
3- now the magic happens:
// 10 => n >= 0;
printf("%s", table[0][n]);
returns -> malloc(): corrupted top size Aborted (core dumped)
in that moment I tried everything a noob would do , so somehow I figured out that the 3rd string test3 is the problem.
so if I remove the table[0][3] line, all works great !!
table[0][1] = "test1";
table[0][2] = "test2";
//table[0][3] = "test3";
table[0][4] = "test4";
...
table[0][n] = "testn";
// 10 => n >= 0;
printf("%s", table[0][n]);
returns => "testn";
EDIT
for Vlad From Moscow
that works:
for(int i=0; i<10; i++{
table[0][n] = "test";
//here works
printf("%s", table[0][n];
}
//here also works fine
printf("%s", table[0][3];
You declared the pointer table like
char*** table;
So the expression table[0] used in this statement
table[0] = malloc(sizeof(char) * 20);
has the type char ** and you allocated memory for 20 characters.
If sizeof( char * ) is equal to 8 then the allocated memory can accommodate only two pointers of the type char *. If sizeof( char * ) is equal to 4 then the allocated memory can accommodate only 5 pointers of the type char *.
You need to do something like the following
char*** table;
table = malloc(sizeof(char**) * 10);
//create array inside table
for ( size_t i = 0; i < 10; i++ )
{
table[i] = malloc(sizeof(char *) * 20);
}
These memory allocations will simulate a two dimensional array of the type char * table[10][20].
On the other hand, you could at once allocate memory for a two-dimensional array like
char * ( *table )[20] = malloc( sizeof( char *[10][20] ) );

how to allocate arrays (in array of pointers) C -- can it be done in one line? with malloc

is there a simple one liner I can use in C to allocate arrays in (pointer of arrays)
This line creates 10 pointers of arrays
char *out[10];
I can't do this
char *out[100]=(char[10][100])malloc(sizeof(char)*10*100);
error: cast specifies array type
same error with
char *out[10]=(char*[10])malloc(sizeof(char)*10*100);
do I need to do it in loop like this
int main()
{
char *out[10];
int x=0;
while(x<10)
{
*(out+x)=malloc(sizeof(char)*100);// is this line correct?
x++;
}
*out[0]='x';
printf("%c\n",out[0][0]);
free(out);
return 0;
}
but this cause warning that
req.c:75:3: warning: attempt to free a non-heap object ‘out’ [-Wfree-nonheap-object]
75 | free(out);
so do I need to allocate and free each array in (array of pointers) in loop
Can't I do allocation and free arrays in array of pointer in one line instead of loop?
or is there anything thing in my loop wrong too
To allocate an array of pointers to strings, you need to do:
char** out = malloc(sizeof(char*[10]));
The whole point of using this form is that each pointer in that array of pointers can be allocated with individual size, as is common with strings. So it doesn't make sense to allocate such with a "one-liner", or you are using the wrong type for the task.
In case you don't need individual sizes but are rather looking for a char [10][100] 2D array with static size, then the correct way to allocate such is:
char (*out)[100] = malloc(sizeof(char[10][100]));
You can allocate the full array in one single step and have pointers inside that array:
char *out[10];
data = malloc(100); //sizeof(char) is 1 by definition
for (int x=0; x<10; x++) {
out[i] = data + x * 10;
}
*out[0] = 'x';
printf("%c\n",out[0][0]);
free(data); // you must free what has been allocated
int i;
char** out = (char**)malloc(sizeof(char*)*10);
for(i = 0; i<10;i++)
out[i] = (char*)malloc(sizeof(char)*100);
out[1][1] = 'a';
OR with same dimensions
#include <stdio.h>
#include <stdlib.h>
void main()
{
int r = 10, c = 100; //Taking number of Rows and Columns
char *ptr, count = 0, i;
ptr = (char*)malloc((r * c) * sizeof(char)); //Dynamically Allocating Memory
for (i = 0; i < r * c; i++)
{
ptr[i] = i + 1; //Giving value to the pointer and simultaneously printing it.
printf("%c ", ptr[i]);
if ((i + 1) % c == 0)
{
printf("\n");
}
}
free(ptr);
}

2D array as pointer to char array

I am playing with some code in C and also I am trying to understand relationship between pointers and arrays. As you probably know, when I want to make array it could be done like this:
char * arr = "abc";
or
char arr[] = {'a','b', 'c'};
But when I want to do 2D array. It must be done like this
char arr[3][10];
Why declaration like this crashes when I try to load string to that.
char * names[3];
for ( int i = 0; i < 3; i++ ) {
printf("Enter name %d: ", i+1 );
scanf("%s", names[i]);
}
// print names
printf("\nEntered names are: \n");
for ( int i = 0; i < 3; i++ ) {
printf("%s\n", names[i] );
}
It should be 2D array right? Because array is basically pointer.
Could you please explain that?
Thanks.
char * names[3];
Is not a 2D array, it's an array of three pointers to char, if you want to store char arrays in it you must allocate memory to each individual pointer, something like:
for(size_t i = 0; i < 3; i++){
names[i] = malloc(/*length your array of chars*/);
}
You can then store char arrays, using you example:
for(size_t i = 0; i < 3; i++){
printf("Enter name %ld: ", i + 1 );
scanf("%29s", names[i]); //for a malloc size of 30
}
Note that you must be careful with scanf, if the inputed string is longer then the memory allocated to store it you will have stack smashing, i.e. for names[i] with size of 30, you should use %29s specifier, instead of %s. Though this approach is not whitout its issues, namely possible characters left in stdin buffer, it's definitely safer.
Alternatively you can assign them string literals (in this case it's best to declare the array as const, otherwise if you try to edit one or more characters it'll result in a segfault):
const char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = "My string literal";
}
You can also make them point to existing char arrays:
char arr[3][10];
char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = arr[i];
}
char * names_1[3];
It's not a pointer. It's an array of pointers.
char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;
Now it's a pointer to your 2D-Array. Just define a function and try to use it with your "pointers" as parameters.
void print_names(char names[][10], const int row){
for(int i=0; i<row; i++)
puts(names[i]);
}
Now call it with:
print_names(names_2, 3);
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG
And you'll see the difference.
char* names[3] is not strictly a 2D array (they don't exist in C or C++); it's an array of arrays. So each element of names contains simply a char*, which has not been initialised.
Note also that a c-style string is a null-terminated array of chars, so your original arr is not a c-style string. To make it a c-style string you would need:
char arr[] = {'a','b','c',0};
making it an array of length 4, not 3.
Missing off the null-terminator will mean that most functions will run off the end of the allocated memory, because they won't know when the string stops.
pointer is a type of variable, which can only contain an address of another variable. It can't contain any data. You can't store data into a pointer.Pointers should point at memory location.
So to use a pointer in the right way ,it must always point at a valid memory location in stack or memory dynamically allocated in heap.
this char * names[3] is an array of pointers ,so you need to reserve memory for it and then initialize it.You need to use some thing like this:
char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}
also you should allocate memory for char *arr too.
char *arr=malloc(strlen(data)+1)
then initialized it.

2d array of strings declaration in C

How to allocate a 2-d array of strings............By that I mean if t[][] is the array
{char t[0][0]} should store a string,
{ char t[0][1] } should store a string etc........Can we use {char ***t } to accomplish this ..If so how should I approach it?? Or can we also go about doing it like
{ char **t[10] } , where 10 is the maximum length of any string I am going to enter in the array...
well first of all you said: By that I mean if t[][] is the array {char t[0][0]} should store a string, { char t[0][1] } , if t[0][1] would store a string then it's not a 2D array you want but rather a 3D array , in a 2D array it's t[0] that stores the string (because a string is an array , and 2D arrays are arrays of arrays) , having said that I'm going to show you how to Dynamically allocate memory for a 2D array and you can use the principle to create a 3D one.
char **matrix = NULL;
int i ;
matrix = malloc(sizeof(char) * ROWS);
for(i = 0 ; i < COLUMNS ; i++)
matrix[i] = malloc(sizeof(char));
and there you have it , just don't forget to use free after you're done with that array
Edit :
to free a dynamically allocated 2D array you need to free the last thing you malloced first , like this :
for(i = 0 ; i < COLUMNS ; i++)
free(matrix[i]);
free(matrix);
Edit:
To do this you will have to specify the cardinal of the second dimension and the maximum lenght of the string. Then use the name of the array with sizeof and the number of strings you want to allocat for:
#include <stdio.h>
#include <string.h>
int main(void) {
/* 10 is the lenght of each string and 1 for the '\0'
10 is the number of strings per each 2D array
5 is the number of 2D arrays */
char (*array)[10][10+1] = malloc(5*sizeof(*array));
// Exemple
strcpy(array[0][0], "hello, world");
printf("%s\n", array[0][0]);
return 0;
}
Live Demo
You have to allocate an array of pointers to pointers to char, which is:
char ***array = (char ***)malloc(sizeof(char**)*ARRAY_X);
Then, you have to allocate each single array of pointers to chars:
for(int i = 0; i < ARRAY_X; i++){
array[i] = (char **) malloc(sizeof(char *)*ARRAY_Y);
}
Finally you have to allocate strings:
for(int i = 0; i < ARRAY_X; i++){
for(int j = 0; j < ARRAY_Y; j++){
array[i][j] = (char *) malloc(sizeof(char)*ARRAY_Z);
}
}
ARRAY_X and ARRAY_Y and ARRAY_Z are int indicating the dimension of the 2-d array of strings (which is a 3-d array of chars).

Initialize array of characters using pointers

This problem is driving me crazy, I'm sure I'm missing something. I need to initialize an array of chars using only pointers. Below is the code I have so far:
int p2(){
/* Implements problem 2 of lab */
// Create an array
char **s = (char**)malloc( 11 *sizeof(char));
char *p = *s;
char start ='A';
while( p != s+10){
*p = start;
start++;
p++;
}
return(0);
}
The problem I'm having is I don't know how to address the characters inside of the array. I understand the base address of the array is **s, and the pointer to the first element is *s. What I don't understand is how to get to **s+10 (i.e. the end of the array).
Can anyone shine some light for me??? Please!
EDIT: Ok, looks like I misunderstood the question. I appears I need to create an array of strings (thus the char ** allocation). Then I need to loop through this array, and assign each string (i.e. char *) a value 15 chars long. Please let me know if I'm understanding this correctly:
char **strings ==> strings[0 ... n ] where each element is a pointer to a char (possibly an array). There for *string ==> strings[0], *(string+1) = strings[1], etc etc.
Am I close or way off?
char **s is 2 dimensional array of characters, or array of C strings if you want.
If you want to use array of characters you should use:
char *string = (char*)malloc( 11 *sizeof(char));
If you really want to initialize array of strings, at first step you're initializing array of pointers, that's:
char **s = (char**)malloc( 11 *sizeof(char *));
Please note that I'm using char * inside sizeof. Than when you may use strings, but at first you must initialize each string.
s[0] = (char*) malloc( 15*size(char)); // This is actually string, 14 characters long (NULL terminated)
char *p = s[0]; // p is pointer to beginning of your string now
And there's two way how to address your string:
s[0][3] // 4th character of your string
p[3]
Or if you want to use just pointers:
char *p = *(s+0);
*(p+3); // 4th character
*((*(s+0))+3) // To do it "hardcore"
EDIT: added an example
When you have **char p and use p++ or p + 1, C increases memory address. *p operator tells compiler that you now want to work with data stored in memory, not with pointer. Therefor those two syntax do the same:
p[10] = 'a';
*(p+10) = 'a';
So if you want traverse both your dimensions, you should use:
for( int i = 0; i < 11; i++){
char *p = *(s+i);
for( int j = 0; j < 10; j++){
*(p + j) = 'a'; // Say you wanna fill them with as
}
// You may also use this syntax:
while( p < (*(s+i) + 10)){ // or use != instead of <
*p = 'a';
p++;
}
}
I think you meant this:
char *s = (char*) malloc(11 *sizeof(char));
char *p = s;
In which case you'd address the characters with s[x]
First, you don't need a char ** unless you need an array of arrays.
Second, you can get to the end of the array with (*s)[10] or *((*s)+10)
Third, in C programming, don't cast the result of malloc()
The code is falling apart here.
char **s = (char**)malloc( 11 *sizeof(char));
You're allocating enough memory for 11 chars, which sounds like what you want to do.
However, you're casting the address to those 11 chars to a (char**) as if you were allocating space for pointers, not chars.
Why should you use a double pointer for creating an array of chars?
char *s = (char *) malloc(10 * sizeof(char));
char *start = s; // save starting pointer
for(; s < start+10; s++)
*s = 'a';
return 0;
If you allocate char ** essentially you're allocating an array of pointers to char(eg. array of strings). If you need char array, allocate char array. If you start working with pointers a design of stack and heap can be really helpful.

Resources