I would like to have a dynamic 2D array of chars, max 200 and scan to it.
I am not really sure how to do this, all I came up with is to define the dynamic arrays (and I don't even know if it is right):
char **arr = (char **)malloc( (len+1) * sizeof(char*) );
for (i=0; (len+1)>0; i++)
char *arr1 = (char *) malloc ( (len+1) * sizeof(char) );
But I am not sure what to put in the (len) - let's say I would like an array of 51x150, depending on the scanned input.
How to allocate the array based on the scanned value and print it?
An example of input:
####.#...##
##.##.#.###
##.###.#.##
#.##.##.#..
You probably want to use a real 2D array and not a segmented look-up table.
size_t x = 51; // user input
size_t y = 150; // user input
char (*arr)[y] = malloc( sizeof(char[x][y]) );
...
arr[i][j] = something;
...
free(arr);
This is much faster and safer than a segmented look-up table. This also allows you to memcpy data in and out of the array, even if that data is larger than one line.
Related
I wanted to copy the content of a two dimensional array into another two dimensional char array. I used the following for loop with memcpy but it is not working as desired. So I have two questions.
What is wrong with this code? and
Is there a way to do it without use of iteration?
for (int i = 0; i < count; i++) {
memcpy(&buf_copy[i], buf[i], sizeof(buf[i]));
}
Both buf and buf_copy are 2d dynamic char arrays.
Edit: declarations of the arrays
char **buf;
char **buf_copy;
EDIT 2: Here is how memory is allocated to them
void intit_buf()
{
buf = (char**)malloc(BUFFER * sizeof(*buf));
for (int i = 0; i < BUFFER; i++)
buf[i] = (char*)malloc(sizeof(char) * 33);
//initialize buf_copy
buf_copy = (char**)malloc(BUFFER * sizeof(*buf_copy));
for (int i = 0; i < BUFFER; i++)
buf_copy[i] = (char*)malloc(sizeof(char) * 33);
}
What is wrong with this code?
The first and last parameters of the function call.
Change this:
memcpy(&buf_copy[i], buf[i], sizeof(buf[i]));
to this:
memcpy(buf_copy[i], buf[i], 33);
since you need to give the size of the column, not the size of a pointer!
Moreover, notice that you need to pass buf_copy, just like you did for buf, without taking the address of it or something, since memcpy() expects pointers for its two first parameters, and buf_copy[i] and buf[i] are pointers already.
Is there a way to do it without use of iteration?
It cannot be done without ireation because malloc() may not have returned contigeous memory. Read more in C / C++ How to copy a multidimensional char array without nested loops?
PS: Unrelated to your problem, but in general: Do I cast the result of malloc? No!
This question already has answers here:
C dynamically growing array
(10 answers)
Closed 6 years ago.
Can anyone explain to me the easiest way to create dynamically a 2D string array with stable second dimension? I've got a txt file with some strings in it and I want to transfer this txt to an array. So I want to associate the txt line number with the first dimension and the string itself with the second dimension. The second dimension is the number of characters in every row (which is stable because every line in the txt has a certain syntax) So if I have in my txt:
hello how (newline)
are youuu
*(I wrote youuu because as I said, every line has the same number of characters).
I want something like:
array[0]["hello how"],
array[1]["are youuu"]
Non numerical keys are not allowed in C. You're trying to do some PHP and JavaScript nonsense in a language that only works with numbers.
But, with C there is always 2 roads to hell.
char *lookup_key(int index, char *key) { ... }
printf(lookup_key(0, "hello how"));
If you know the length of the strings and how many you have, you can configure the array like this
char strings[numLines][strLen+1];
you can then access the array like this
strcpy(strings[1], "test2");
If you don't know anything beforehand, you need a pointer to pointer array and then use malloc to allocate space as the array grow, free when you are done.
dynamic in C implies you will need to use one of [c][m]alloc to create memory for your strings. And 2D implies an array of char arrays. Assuming you know the number of strings and the longest string needed, the following will create memory to contain them:
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
The following will free the memory created above:
void free2DStr(char ** a, ssize_t numStrings)
{
int i;
for(i=0;i<numStrings; i++)
{
if(a[i]) free(a[i]);
}
free(a);
}
These can be called like this:
...
char **strArray = {0};
strArray = Create2DStr(10, 20);
//Use strArray...
free2DStr(10);
Giving 10 arrays, each able to contain 20 char, plus a NULL. (The + 1 after maxStrLen provides the extra space for the NULL).
If you want to save each line of the file as a row in the array, use a 2D array of char:
char fileContents[NUM_LINES][LINE_LENGTH + 1]; // +1 for zero terminator
If you don't know how many lines you have up front, you'll need to do some memory management. First, you'll need to allocate an initial extent:
#define INITIAL_EXTENT 20 // or some good starting point
char (*fileContents)[LINE_LENGTH + 1] = malloc( sizeof *fileContents * INITIAL_EXTENT );
if ( !fileContents )
{
// malloc failed; fatal error
fprintf( stderr, "FATAL: could not allocate memory for array\n" );
exit( EXIT_FAILURE );
}
size_t numRows = INITIAL_EXTENT; // number of rows in array
size_t rowsRead = 0; // number of rows containing data
As you read from the file, you'll check to make sure you have room in the array; if you don't, you'll need to extend the array with a realloc call, which is a potentially expensive operation. A common technique is to double the size of the array each time you extend it - that minimizes the total number of realloc calls. The risk is some internal fragmentation if you double the array size because you need just one more row, but that's probably something you can analyze around:
char tmpBuf[LINE_LENGTH + 2]; // account for newline in input buffer
while ( fgets( tmpBuf, sizeof tmpBuf, inputFile ) )
{
/**
* Check to see if you have any room left in your array; if not,
* you'll need to extend it. You'll probably want to factor this
* into its own function.
*/
if ( rowsRead == numRows )
{
/**
* Use a temporary variable for the result of realloc in case of failure
*/
char (*tmp)[LINE_LENGTH + 1] =
realloc( fileContents, sizeof *fileContents * ( 2 * numRows ) );
if ( !tmp )
{
/**
* realloc failed - we couldn't extend the array any more.
* Break out of the loop.
*/
fprintf( stderr, "ERROR: could not extend fileContents array - breaking out of loop\n" );
break;
}
/**
* Otherwise, set fileContents to point to the new, extended buffer
* and update the number of rows.
*/
fileContents = tmp;
numRows *= 2;
}
// strip the newline from the input buffer
char *newline = strchr( tmpBuf, '\n' );
if ( newline )
*newline = 0;
strcpy( fileContents[rowsRead++], tmpBuf );
}
I am new in whole C programming thing (comming from Java), and honestly its really confusing. Ok to the problem I am trying to allocate contigous chunk of data for my 2D array of strings (Guessing its something like 3D array??). All I have is this i believe contiguous allocation for Array of strings?
Can someone help me out with 2D array please?
And yes I know size before running the program, its defined so ROWS for rows, COLS for columns and NAME for length of string.
char **people = malloc(COLS * sizeof(char *));
people[0] = malloc(COLS * NAME);
for(int i = 1; i < COLS; i++)
people[i] = people[0] + i * NAME;
If you actually know the size of the array before running the program, you don't need to dinamically allocate the memory with malloc, you could create a 2D static array. In your case, as it is a 2D array of strings, it could be declared as char * array[ROWS][COLS], and then you could asign a string to a specific element this way: array[nrow][ncol]="Your String".
C, unlike Java, actually has a concept of multidimensional arrays; so unless there's a specific reason you want a char * * *, you might prefer to write:
char (*people)[COLS][NAME] = malloc(ROWS * sizeof(*people));
which sets people to be a pointer to the first of ROWS dynamically-allocated two-dimensional character arrays.
Due to pointer "decay", where an expression of array type will double as a pointer to the first element of the array, you can use people very much as if it were a char * * *; for example, people[3][4] will point to the string in row 3, column 4. The only restriction is that you can't write something like people[3][4] = ... to suddenly change what string to point to. But it sounds like you don't want to do that, anyway?
Note: the above is assuming that you are intentionally using dynamic memory allocation. However, I do recommend you consider Sizigia's suggestion to use static memory, which is the same sort of storage as is used for global variables. If you write something like
static char people[ROWS][COLS][NAME];
then the memory will be allocated just once, at the start of the program, and reused by all calls to the function that declares it.
You can define a char * using typedef so it's better for you to understand the code. Then all you have to do is to dynamically allocate a 2D array of your defined type (in the example below, I defined it as a "string"):
typedef char * string;
string ** people;
people = malloc(ROWS * sizeof(string));
for(int i = 0; i < ROWS; i++){
people[i] = malloc(COLUMNS * sizeof(char));
}
You can access it using the normal array sintax, people[i][j].
I tried to make a dynamic 5x5 int array
int **data=malloc(5*5);
But I get segmentation fault on trying to access it.
You need to allocate memory for the 2d-array you want to make (which I think you understand). But first, you will have to allocate the space for pointers where you will store the rows of the 2D-array.
int **data=(int**)malloc(sizeof(*data)*5); //Here 5 is the number of rows
Now you can allocate space for each row.
for(int r=0;r<5;r++){
data[r]=(int*)malloc(sizeof(**data)*5);//here 5 is the width of the array
}
If you want contiguous block of memory for the whole array, you can allocate a single dimension array of size 25, and access it like data[r*5+c].
PS: Instead of sizeof(*data) and sizeof(**data), you can use sizeof(int*) and sizeof(int) to avoid confusion with *
PS: If you are not using C++, removing the casts from return value of malloc is better (see comments).
If you want a single contiguous memory block to hold 5x5=25 integers :
int *data = malloc(5*5*sizeof(*data));
If you want a 2d array with size 5x5
int **data = malloc(5*sizeof(*data));
for (int i=0; i<5; ++i)
data[i] = malloc(5*sizeof(**data));
There are two possibilities. The first one is indeed to allocate a two-dimensional array:
int ( *data )[5] = malloc( 5 * 5 * sizeof( int ) );
In this case one contiguous extent is allocated for the array.
The second one is to allocate at first a one-dimensional array of pointers and then allocate one-dimensional arrays pointed to by the already allocated pointers.
For example
int **data = malloc( 5 * sizeof( int * ) );
for ( size_t i = 0; i < 5; i++ )
{
data[i] = malloc( 5 * sizeof( int ) );
}
In this case there are allocated in fact 6 extents of memory: one for the array of the pointers and other 5 for arrays of integers.
To free the allocated memory in the first example it is enough to write
free( data );
and in the second example you need to write the following
for ( size_t i = 0; i < 5; i++ ) free( data[i] );
free( data );
If you want to treat the array as a 2D array (a[i][j]) and you want all the array elements to be contiguous in memory, do the following:
int (*data)[5] = malloc( sizeof *data * 5 );
If you also want to be table to determine the size of the array at run time and your compiler supports variable-length arrays1:
size_t rows, cols;
...
int (*data)[rows] = malloc( sizeof *data * cols );2
If your compiler does not support VLAs and you still want to determine the array size at runtime, you would do:
size_t rows, cols;
...
int **data = malloc( sizeof *data * rows );
if ( data )
{
for ( size_t i = 0; i < rows; i++ )
{
data[i] = malloc( sizeof *data[i] * cols );
}
}
The downside of this approach is that the rows of the array are not guaranteed to be contiguous in memory (they most likely won't be). Elements within a single row will be contiguous, but rows will not be contiguous with each other.
If you want to determine the array size at runtime and have all the array elements be contiguous in memory but your compiler does not support variable-length arrays, you would need to allocate a 1D array and manually compute your indices (a[i * rows + j]):
int *data = malloc( sizeof *data * rows * cols );
1. VLAs were introduced with C99, but then made optional in C2011. A post-C99 compiler that does not define the macro __STDC_NO_VLA__ should support VLAs.
2. Caution - there is some question whether sizeof *data is well-defined in this example; the sizeof expression is normally evaluated at compile time, but when the operand is a VLA the expression is evaluated at run time. data doesn't point to anything yet, and attempting to dereference an invalid pointer leads to undefined behavior. All I can say is that I've used this idiom a lot and never had an issue, but that may be due more to bad luck than design.
Here is the answer:
int ** squaredMatrix;
int szMatrix=10;
squaredMatrix= (int**)malloc(szMatrix*sizeof(int*));
for making 2d arrays you should view them as one array which every block is an array again .
for example in above picture , blue blocks make an array which each blue block is pointing to an array ( every 4 green blocks in a row are an array and blue blocks in a column are the main array)
I'm trying to write more efficient code in a C program, and I need some help getting my pointers and assignments correct. I've shown two methods below, each using the following declarations and strncpy:
int kk, arraysize;
char person_name[100] = "";
char * array_person_name, * array_param;
...
strncpy(person_name, "John Smith", 100);
arraysize = <this value is downloaded from database>;
...
Method A (rectangular array):
array_person_name = malloc( sizeof(char) * arraysize *100 );
array_param = malloc( sizeof(char) * arraysize * 2 );
for (kk = 0; kk < arraysize; kk++) {
strncpy(array_person_name[kk], person_name, 100);
strncpy(array_param[kk], "bt", 2);
}
Method B (ragged array):
for (kk = 0; kk < arraysize; kk++) {
array_person_name[kk] = &person_name;
array_param[kk] = "bt";
}
Notice that the arrays I'm trying to create place the same value into each element of the array. Method A is an (rectangular) array of arraysize elements, each element itself being an array of 100 characters. Method B attempts not to waste storage space by creating an (ragged) array of arraysize elements, where each element is a pointer-to-char.
QUESTION 1: Am I allocating memory (e.g. malloc) correctly in Method A?
QUESTION 2: Does the syntax look correct for Method B?
QUESTION 3: How do I allocate memory for the arrays in method B?
QUESTION 4: Am I correct that Method B is generally preferred?
You are pretty far off here. 1:yes, 2:no, 3:no, 4:yes. I'm not going to do it all, but here are a few hints.
You need space to store the strings and space to store pointers to the strings (the latter isn't strictly necessary for Method A). The first will have type char*, the second will have type char**.
For Method A, you are allocating the string storage correctly, but you need to allocate the storage for the string pointers correctly (hint: you need arraysize instances of a char* pointer). It then gets initialized to pointers which differ from each other by 100 characters.
For Method B, there is no easy way of allocating space to store the strings, as you don't know how much space you'll need. You could iterate through all the strings once just to count their length, or do one malloc per string, or use a fixed size chunk and allocate more when you run out.
Method B uses the same string storage pointer array as Method A. You need to assign the string pointers into the array once you know where they will go.