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.
Related
This question already has answers here:
Dynamic array in C — Is my understanding of malloc and realloc correct?
(3 answers)
Closed 5 years ago.
So for my school project, a large CSV file will be entered through stdin and we will have to sort it based on column and print it out as a sorted csv file.
The step I am on right now is figuring out how to keep reallocing a struct of arrays so that it will grow if there is not big enough to hold the data coming in from stdin. We don't know the exact amount of rows that will be inputted in the CSV file. Right now we just used a static amount to test and see if the values are assigned to the structs.
I am still a beginner at C so I do not clearly know how I would iterate through a pointer like I would iterate through an array. Since we are using a static amount of structs in the array, we can just iterate using array[i] like in Java but how would you iterate through something like *array?
I do not know where to start for creating this dynamic array. I tried
struct array* testArray = (array*)malloc(sizeof(testArray));
but I have no idea how to iterate through it like I did with the static array by using array[i].
Any help would be greatly appreciated, sorry for the wall of text...
You can navigate through a malloced space the same way as with an array (using indicies), but it seems that your main issue lies in your use of malloc. Malloc's argument is the size in number of bytes that you want to allocate. So if you want to have an array of structs, you would first need to find out how many bytes one struct contains using sizeof(struct array), and then determine how large of an array you want, let's say N. So that line of code should look more like struct array* testArray = malloc(N * sizeof(struct array));. The return value of malloc will be a void pointer containing the memory address of the first byte of allocated space. Upon assigning this value to testArray, it will be type-casted to the assigned variable type (struct array *). Now you can use pointer arithmetic to access a specific index i with *(testArray + i), or simply testArray[i]. If you find that N was not a sufficient size, you can use realloc to increase the array size to 2N, or whatever size deemed necessary.
struct array* testArray = (array*)malloc(sizeof(testArray));
is a little wrong as you only allocate 1 element of testArray.
It is more like:
struct A
{
int a;
int b;
....
};
struct A* arr = malloc( N * sizeof(struct A) );
^^^
N element of struct A
int j;
for (j=0; j<N; ++j) // Iterate it like any other array
{
arr[j].a = 5;
arr[j].b = 42;
....
}
Use realloc when you need the array to grow.
When reading from a file/stdin it could look like (based on comment from David C. Rankin):
int n=0; // Count of the number of structs read from the file
struct A* arr = malloc( N * sizeof(struct A) );
while (read line from file)
{
arr[n].a = val1;
arr[n].b = val2;
++n; // Increment count
if (n == N) // Check if current array is full, i.e. realloc needed
{
// realloc array to 2 * N; N = N * 2
}
}
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 am using GTK, and I am not sure with malloc() function here. Valgrind gives me a memory leak, what I am doing bad?
at first I create pointer to pointer to pointer to GTK widget, because I need three dimensional array.
GtkWidget*** widgets;
and I am using malloc like this:
widgets = malloc((1)*sizeof(GtkWidget**));
for(i = 0; i<= l-1; i++) // l = 4 in my case
{
widgets[i] = malloc((1)*sizeof(GtkWidget*));
for(j = 0; j<=3; j++) // 4 is number of elements in this dimension
{
widgets[i][j] = malloc((1)*sizeof(GtkWidget));
}
}
and at the end I am doing this:
widgets[0][0] = gtk_menu_item_new_with_label("MyLabel");
gtk_menu_shell_append(GTK_MENU_SHELL(indicator_menu), widgets[0][0]);
my array can be smaller and bigger, so I am using dynamic allocation of array, my maximal array indexes are something like widgets[3][3].
I did not post whole code, because it is pretty long, I sent here just the parts for which was valgrind complaining to. What I am doing bad? thank you.
You're only allocating the size of a pointer, when you mean to allocate an array of pointers.
// this will allocate a single character pointer
char ** ptr = malloc(1 * sizeof(char *));
// this will allocate n character pointers
char ** ptr = malloc(n * sizeof(char *));
So if you want a two dimensional array of dimension NxM, you'll need to allocate an array of size N, then walk through that array from 0 to N-1 and allocate arrays of size M.
What you're doing now is assigning pointers returned from malloc to memory you don't own. Is what you actually want a two-dimensional array of pointers to GtkWidget structures?
Using l as a local variable is not a good idea. It is very easy to make a mistake between l and 1, in some editors they look very much the same.
widgets = malloc((l)*sizeof(GtkWidget**)); //is what you needed
iso
widgets = malloc((1)*sizeof(GtkWidget**));
Over here with syntax highlighting the problem immediately appears.
So another suggestion is to for sure use an editor with syntax highlighting
I'm implementing a function in C where I convert a byte[] to an int[]. The problem is that the length of the int[] depends on the contents of the byte[] (not just the length of the byte[]) so I won't know the total length of the int[] until I've iterated the entire byte[]. I'm therefore looking for some form av int-stream or dynamically increasing int-list which I can write to and then convert to a int[] once I'm done writing all the ints. My C-experience is a bit limited at the moment so I'm not really sure what's considered best practice to solve this kind of problem. Any suggestions?
The easiest method would be to allocate the int[] to be the same length (number of elements) as the byte[], and when you're done and know the size, call realloc to shrink it.
This assumes, of course, that interpreting the data would never create more integers than there are bytes in the stream.
There are a few ways of doing this I can think of.
I'm assuming, based on your question, that the transformation of your char[] to the corresponding int[]s is expensive (which is why you want to avoid performing that calculation twice - once to determine the size, and again to populate the contents.
So, here's how I would go about it:
First, is there a maximum size you can associate to the transformation? EX: Is there a maximum 2-to-1 size difference? (For each char in the char[] can it create "up to X" ints?)
If this is the case, and memory usage isn't an issue (you're not super constrained) - Go ahead and alloc the maximum size, populate it as you perform your translation, and realloc when you're done to shrink your memory footprint.
If this is not the case, you're in tougher waters, and should look to non-contiguous schemes - such as a linked list. Once you've performed your translation and built your linked list, you can then allocate space for your array, and visit each element in the linked list to populate the array.
First, inspect byte[] to determine the resulting int[] size. Then use malloc() to allocate the appropriately sized int[] structure.
#include <stdlib.h>
...
// imagine that the resulting int[] size depends on the sum of the bytes
int j, size = 0;
for (j = 0; byte[j]; ++j)
size += byte[j];
int *int_array = (int *) malloc (size);
for (j = 0; j < size; ++j)
int_array [j] = whatever;
First, If you can use C++, then you can just use a vector, which is a dynamically-sized array. Otherwise, you'll have to first iterate through your byte array to determine what the int array size should be, then dynamically allocate the int array. Second, C doesn't have a byte type, so the type normally used is char.
#include <stdlib.h>
char byte_array[ size ];
int i, int_size = 0;
int *int_array;
for ( i = 0; i < size; i++ ) {
int_size += f( byte_array[i] );
}
int_array = (int*) malloc( int_size );
where f() is some function you write that looks at one element of the byte array to help determine how large the int array should be.
I have to write a function in c which will return a dynamic array of strings. Here are my requirements:
I have 10 different examine functions which will return either true or false and associated error text. (error text string is also dynamic).
My function must collect the result(true or false) + the error string and it will be called n examine functions. So my function must collect n results and finally return a dynamic array of strings to other functions.
You can allocate an array of arbitrary length with malloc() (it's like "new" in Java), and make it grow or shrink with realloc().
You have to remember to free the memory with free() as in C there is not garbarage collector.
Check: http://www.gnu.org/software/libc/manual/html_node/Memory-Allocation.html#Memory-Allocation
Edit:
#include <stdlib.h>
#include <string.h>
int main(){
char * string;
// Lets say we have a initial string of 8 chars
string = malloc(sizeof(char) * 9); // Nine because we need 8 chars plus one \0 to terminate the string
strcpy(string, "12345678");
// Now we need to expand the string to 10 chars (plus one for \0)
string = realloc(string, sizeof(char) * 11);
// you can check if string is different of NULL...
// Now we append some chars
strcat(string, "90");
// ...
// at some point you need to free the memory if you don't want a memory leak
free(string);
// ...
return 0;
}
Edit 2:
This is the sample for allocate and expand an array of pointers to chars (an array of strings)
#include <stdlib.h>
int main(){
// Array of strings
char ** messages;
char * pointer_to_string_0 = "Hello";
char * pointer_to_string_1 = "World";
unsigned size = 0;
// Initial size one
messages = malloc(sizeof(char *)); // Note I allocate space for 1 pointer to char
size = 1;
// ...
messages[0] = pointer_to_string_0;
// We expand to contain 2 strings (2 pointers really)
size++;
messages = realloc(messages, sizeof(char *) * size);
messages[1] = pointer_to_string_1;
// ...
free(messages);
// ...
return 0;
}
Consider creating apropriate types suitable for you problem. For example, you can create a struct holding a pointer and sn integer length to represent the dynamic arrays.
Do you have some constraints over
the prototyping of the examine()
function and the function you have
to write ? (let's call it
validate())
You say you have 10 examine() functions, does it mean you will have a maximum of 10 messages/results in the array return by validate() ?
I'm a Java programmer with a C background, so maybe I can highlight a few things for you :
there is no equivalent of Array.length in C : you'll have to supply a side integer value to store the effective size of your array
C arrays can't "grow" : you'll have to use pointers and allocate/reallocate the memory pointed by your array begin pointer as this array grows or shrinks
you should already know that there is no notion of class or method in C, however you can use struct, typedef and function pointers to add some kind of object oriented / genericity behavior to your C programs...
Depending on your needs and obligations, arrays might be a good way to go, or not : perhaps you should try to figure out a way of building/finding an equivalent of the java List interface in C, so that you can add, remove/destroy or sort examine result elements without having to duplicate memory allocation / reallocation / freeing code each time you manipulate your result set (and you should perhaps send a header file with your structs/examine functions to describe what you did for now anyway, and express your needs a bit more precisely, so that we can guide you to the good direction)
Don't hesitate to provide more information or ask for specifics about the above bullets points ;)