I would like it create a 2D array based upon values in a file. I am able to do this by making the array local with the following code:
int main()
{
int a = 5; //this is from a file
int b = 6; //this is from a file
int (*array2d)[a] = malloc(sizeof(int)*a*b);
return 0;
}
However, I would like array2d to be global. The following doesn't work:
int **array2d
int main()
{
int a = 5; //this is from a file
int b = 6; //this is from a file
(*array2d)[a] = malloc(sizeof(int)*a*b);
return 0;
}
Is there any simple way to do this?
Allocation and de-allocation of memory for 2D array you can do with functions:
#include <stdlib.h>
#include <stdio.h>
int ** allocIntArray(int nrows, int ncols)
// allocate memory for 2D array and returns pointer if successful or NULL if failed
{
int r, c; // rows and cols counters
int ** parray; // pointer to array
// allocate memory for rows pointers
parray = (int **) malloc(nrows * sizeof(int *));
if( parray == NULL) // check
{
return NULL; // error sign
}
// allocate memory for each row
for (r = 0; r < nrows; r++)
{
parray[r] = (int*) malloc(ncols * sizeof(int));
if( parray[r] == NULL ) // check
{
// clean memory that was allocated before error
while(--r >= 0)
{
free(parray[r]);
}
free(parray);
return NULL; // error sign
}
}
// return when success
return parray;
}
int freeIntArray(int nrows, int **parray)
// frees memory allocated for 2D array and returns 1 if successful or 0 if failed
{
int r; // rows counter
if( parray == NULL || nrows < 1)
{
return 0;
}
// free memory allocated for each row
for (r = 0; r < nrows; r++)
{
if(parray[r] != NULL)
{
free(parray[r]);
}
}
// free memory allocated for rows pointers
free(parray);
return 1;
}
Having this two functions you can create array of any size, e.g.:
int ** globArr;
int nrows; // number of rows
int ncols; // number of columns
int main(int argc, char * argv[])
{
// let's filename is in argv[1]
if( argc < 2) // we have not filename
{
printf("File name must be given as command line argument!\n");
return 1; // exit from program
}
// when we have filename try to use it
FILE * f = fopen(argv[1], "r");
if( f == NULL ) // we cannot read from file
{
printf("File %s cannot be read!\n", argv[1]);
return 2; // exit from program
}
// when we have file openned for reading
// we try to read first two numbers and use them as size of array
if( 2 != fscanf(f, "%d %d", &nrows, &ncols) ) // we cannot read two numbers
{
printf("ERROR: Wrong file format!\n");
return 3; // exit
}
// check that numbers are positive
if( nrows < 1 || ncols < 1 )
{
printf("ERROR: Wrong data size!\n");
return 4; // exit
}
// now we can allocate memory
globArr = allocIntArray(nrows, ncols);
// check that array allocated
if(globArr == NULL)
{
printf("ERROR: Cannot allocate memory!\n");
return 5; // exit
}
// and start a loop to read data from file
int r, c;
for(r = 0; r < nrows; r++)
{
for(c = 0; c < ncols; c++)
{
if (feof(f)) // end of file reached
{
printf("ERROR: Unexpected end of file!\n");
return 6; // exit
}
if( 1 != fscanf(f, "%d", &globArr[r][c]) )
{
printf("ERROR: Wrong file format!\n");
return 6; // exit
}
}
}
fclose(f);
// Now work with data
// . . .
return freeIntArray(nrows, globArr);
}
Note: file format can be different from my. I hope, that program will read files in formats
2 3
10 20 30
40 50 60
or
2 3 10 20 30 40 50 60
or
2
3
10
20
30
40
50
60
where 2 and 3 define size of 2d-array
Related
I'm writing a program to read numbers from a .txt file to then put into a 2-dimensional matrix that I can use to do matrix multiplication with but at this point I'm having alot of trouble getting the portion of my code that scans the file to work properly. I have two randomly generated matrixes that I'm using and for the smaller one it will read the first 400 values but then the rest of the array will be zeros. For the larger one, which is 4000x4000, it will just throw a segmentation fault without even going into the main. Any ideas at what would be causing this? I change ARRAY_SIZE to whatever the array length and Width are.
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 4000
int main(int argc, char *argv[]) {
// Form to read: ./programname #ofthreads inputfilename1 inputefilename2 outputfilename
if(argc != 5) {
printf("Error! usage: ./programname #ofthreads inputfilename1 inputfilename2 outputfilename");
return (EXIT_FAILURE);
}
// get number of threads
int numThreads = atoi(argv[1]);
// make file pointers
FILE *fp1;
FILE *fp2;
// assign pointer to file name
fp1 = fopen(argv[2], "r");
fp2 = fopen(argv[3], "r");
// Error Handling if file doesn't exist
if (fp1 == NULL) {
printf("Error: File 1 does not exist. ");
return (EXIT_FAILURE);
}
if (fp2 == NULL) {
printf("Error: File 2 does not exist. ");
return (EXIT_FAILURE);
}
// initialize arrays
int array1[ARRAY_SIZE][ARRAY_SIZE] = {0};
int array2[ARRAY_SIZE][ARRAY_SIZE] = {0};
// initialize dimension ints
int size1[2];
int size2[2];
// Get Dimensions
fscanf(fp1,"%d ",&size1[0]);
fscanf(fp1,"%d \n", &size1[1]);
fscanf(fp2,"%d ",&size2[0]);
fscanf(fp2,"%d \n", &size2[1]);
int length1 = size1[0];
int width1 = size1[1];
int length2 = size2[0];
int width2 = size2[1];
for(int n = 0; n < length1; n++){
for(int m = 0; m < width1; m++){
fscanf(fp1, "%d ", &array1[m][n]);
}
}
for(int n = 0; n < length2; n++){
for(int m = 0; m < width2; m++){
fscanf(fp1, "%d ", &array2[m][n]);
}
}
// Process file here
// Close file
fclose(fp1);
fclose(fp2);
for(int n = 0; n < width1; n++){
for(int m = 0; m < length1; m++){
// printf("%d ", array1[m][n]);
}
printf("\n");
}
printf("Number of threads = %d\n", numThreads);
printf("Size1 = %d x %d\n", size1[0],size1[1]);
printf("Size2 = %d x %d\n", size2[0],size2[1]);
return 0;
}
2 x 4000 x 4000 ints will most probably take up more stack space than you have available. Allocate the memory dynamically using calloc instead (declared in stdlib.h):
// allocate space for ARRAY_SIZE elements of size int[ARRAY_SIZE] and zero the memory:
int(*array1)[ARRAY_SIZE] = calloc(ARRAY_SIZE, sizeof *array1);
int(*array2)[ARRAY_SIZE] = calloc(ARRAY_SIZE, sizeof *array2);
if(array1 == NULL || array2 == NULL) exit(1);
However, by the looks of it, you don't actually need all that memory in most cases since you get length1, width1, length2 and width2 from the files. Allocate the arrays after you've gotten that input from the files:
if(fscanf(fp1, " %d %d", &length1, &width1) != 2 ||
fscanf(fp2, " %d %d", &length2, &width2) != 2) exit(1);
int(*array1)[width1] = calloc(length1, sizeof *array1);
int(*array2)[width2] = calloc(length2, sizeof *array2);
if(array1 == NULL || array2 == NULL) exit(1);
Then use array1 and array2 just like you did before.
When you are done with them, free the allocated memory:
free(array1);
free(array2);
Process stack size is limited (few MiBs). It varies between systems based on OS implementation. If you need anything over that, better get it from heap (Memory management calls).
int rows = 4000;
int cols = 4000;
int **array = (int**) malloc (rows * sizeof(int*));
if (!array) {
perror("malloc1");
exit(1);
}
for (ri = 0; ri < rows; ++ri) {
array[ri] = (int*) malloc (cols * sizeof(int));
if (!array[ri]) {
perror("malloc2");
exit(2);
}
}
Remember to free the allocated memory in reverse order. First the columns' (loop) then the rows'.
Edit:
3. Assuming you allocated both array1 & array2 using malloc() calls.
Reading array2 contents
fscanf(fp1, "%d ", &array2[m][n]);
shouldn't that be fp2?
Since you're going to do matrix multiplication you need to verify the order of matrices.
first write code for smaller matrix dimensions without malloc() & without reading data from files.
I need to sort ints from a file in ascending order and print them to the standard output. I can't modify the structure of the file.
The txt file looks like this:
41
65
68
35
51
...(one number in a row)
My program works just fine for small files, but I have to optomize it for larger files (like 3 million numbers) using malloc, but don't know exactly where and how. I'd like to ask for help in this. (I'm a beginner)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER 100000
int sort(int size, int arr[])
{
for (int i = 0; i < size - 1; i++)
{
for (int j = 0; j < size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int swap = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = swap;
}
}
}
}
int main(int argc, char *argv[])
{
char *filename = argv[1];
char s[20];
if (argc == 1)
{
fprintf(stderr, "Error! Input then name of a .txt file\n");
exit(1);
}
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "Error! Can't open %s\n", filename);
exit(1);
}
int arr[BUFFER];
int i = 0;
int size = 0;
while ((fgets(s, BUFFER, fp)) != NULL)
{
s[strlen(s) - 1] = '\0';
arr[i] = atoi(s);
++i;
++size;
}
fclose(fp);
sort(size, arr);
for (int i = 0; i < size; ++i)
{
printf("%d\n", arr[i]);
}
return 0;
}
Your program could look like this:
#include <stdlib.h>
#include <stdio.h>
static int numcompar(const void *a, const void *b) {
const int *x = a;
const int *y = b;
// it is tempting to return *x - *y; but undefined behavior lurks
return *x < *y ? -1 : *x == *y ? 0 : 1;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
// TODO: handle error
abort();
}
char *filename = argv[1];
// open the file
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
abort();
}
// this will be our array
// note realloc(NULL is equal to malloc()
int *arr = NULL;
size_t arrcnt = 0;
// note - I am using fscanf for simplicity
int temp = 0;
while (fscanf(fp, "%d", &temp) == 1) {
// note - reallocating the space each number for the next number
void *tmp = realloc(arr, sizeof(*arr) * (arrcnt + 1));
if (tmp == NULL) {
free(arr);
fclose(fp);
abort();
}
arr = tmp;
// finally assignment
arr[arrcnt] = temp;
arrcnt++;
}
fclose(fp);
// writing sorting algorithms is boring
qsort(arr, arrcnt, sizeof(*arr), numcompar);
for (size_t i = 0; i < arrcnt; ++i) {
printf("%d\n", arr[i]);
}
free(arr);
}
Note that reallocating for one int at a time is inefficient - realloc is usually a costly function. The next step would be to keep the number of the size of the array and "used" (assigned to) elements of the array separately and reallocate the array by a ratio greater then 1. There are voices that prefer to use the golden ratio number in such cases.
To read an undetermined number of entries from the input file, you can allocate and reallocate an array using realloc() as more entries are read. For better performance it is recommended to increase the allocated size by a multiple instead of increasing linearly, especially one entry at a time.
Your sorting routine is inappropriate for large arrays: insertion sort has quadratic time complexity, so it might take a long time for 3 million items, unless they are already sorted. Use qsort() with a simple comparison function for this.
Here is a modified program:
#include <stdio.h>
#include <stdlib.h>
static int compare_int(const void *pa, const void *pb) {
int a = *(const int *)pa;
int b = *(const int *)pb;
// return -1 if a < b, 0 if a == b and +1 if a > b
return (a > b) - (a < b);
}
int main(int argc, char *argv[]) {
if (argc == 1) {
fprintf(stderr, "Error! Input then name of a .txt file\n");
exit(1);
}
char *filename = argv[1];
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Error! Can't open %s\n", filename);
exit(1);
}
char buf[80];
size_t n = 0, size = 0;
int *array = NULL;
/* read the numbers */
while (fgets(buf, sizeof buf, fp)) {
if (n == size) {
/* increase size by at least 1.625 */
size_t newsize = size + size / 2 + size / 8 + 32;
int *newarray = realloc(array, newsize * sizeof(*array));
if (newarray == NULL) {
printf("cannot allocate space for %zu numbers\n", newsize);
free(array);
fclose(fp);
exit(1);
}
array = newarray;
size = newsize;
}
array[n++] = strtol(buf, NULL, 10);
}
fclose(fp);
/* sort the array */
qsort(array, n, sizeof(*array), compare_int);
for (size_t i = 0; i < n; i++) {
printf("%d\n", array[i]);
}
free(array);
return 0;
}
I'm allocating memory for my int *occurrences int *wordCounts and char **uniqueWords pointers and then at the end of the function that allocates the memory, i free them. However, when i compile the program i get an double free or corruption (!prev) aborting error. Is it caused by malloc,free or could it be due to how i initialize them inside the for loop ?
PS: I'm talking about the sortedCount() method, located towards the end
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define MAX_STRING_SIZE 512 /* each line in the file can have up to 512 chars */
void populateWordsArray(int);
void reverse(int);
void first(int);
void middle(int);
void last(int);
int count(int, char*, int);
void sortedCount(int);
void determineUniqueWords(int *,char **, int);
void *malloc_or_end(size_t);
void* malloc_or_end(size_t sz) {
void *pointer;
pointer = malloc(sz);
if(pointer == NULL) {
printf("Out of memory, terminating.\n");
exit(-1);
}
return pointer;
}
/* turn into local */
FILE *file;
char **wordList;
void determineUniqueWords(int *occurrences, char **word, int N) {
int i = 0;
int j = 0;
for(i = 0; i < N; i++) {
if(occurrences[i] < 1) {
continue;
}
for(j = i + 1; j < N; j++) {
if(occurrences[j] == 1 && (strcmp(word[i],word[j])) == 0) {
occurrences[i]++;
occurrences[j] = 0;
}
}
}
}
/**
* Function populateWordsArray: reads N words from
* the given file and populates the wordList array with them.
* Has one argument: int N - the number of words to read.
* */
void populateWordsArray(int N) {
int i = 0;
while(i < N && (fscanf(file,"%s",wordList[i]) == 1)) { /* fscanf returns the number of successfully read items. If it's not 1, the read failed. Same as checking if fscanf reads the eof char. */
i++;
}
}
/**
* Function reverse: prints the words of the
* text file in reverse order.
* */
void reverse(int N) {
int i = 0;
for(i = N-1; i >= 0; i--) {
if(i == 0) {
printf("%s \n",wordList[i]);
} else if(strcmp(wordList[i],"") == 0) { /* improve this in main-> memory allocation */
continue;
}else {
printf("%s ",wordList[i]);
}
}
return;
}
/**
* Function first: Prints the first char of each
* word in the file.
* */
void first(int N) {
char firstChar;
int i = 0;
for(i = 0; i < N; i++) {
firstChar = *wordList[i];
printf("%c",firstChar);
}
printf("\n");
return;
}
/**
* Function middle: Prints the middle char of each word
* from the given file.
* */
void middle(int N) {
int middleIndex = 0;
int i = 0;
char midChar;
for(i = 0; i < N; i++) {
if((strlen(wordList[i]) % 2) == 0) { /* artios */
middleIndex = ((strlen(wordList[i]) / 2) - 1);
midChar = wordList[i][middleIndex];
}
else { /* peritos */
middleIndex = (int) ceil((strlen(wordList[i]) / 2));
midChar = wordList[i][middleIndex];
}
printf("%c",midChar);
}
printf("\n");
return;
}
/**
* Function last: Prints the last char of each
* word from the given file.
* */
void last(int N) {
int i = 0;
char lastChar;
int lastPos;
for(i = 0; i < N; i++) {
lastPos = strlen(wordList[i]) - 1;
lastChar = wordList[i][lastPos];
printf("%c",lastChar);
}
printf("\n");
return;
}
/**
* Function count: Prints the number of times
* that the selected word is found inside the N first words
* of the file.
* */
int count(int N, char *word, int callID) {
int i = 0;
int count = 0;
for(i = 0; i < N; i++) {
if(strcmp(word,wordList[i]) == 0) {
count++;
}
}
if(callID == 0) { /* if callID == 0 (main called count and we want the output) */
printf("%d",count);
printf("\n");
}
return count;
}
void sortedCount(int N) {
int i,j = 0;
int *occurrences;
int *wordCounts;
char **uniqueWords;
/* mem allocation */
uniqueWords = malloc_or_end(N * sizeof(char*)); /* worst case: every word is unique */
wordCounts = malloc_or_end(N * sizeof(int));
occurrences = malloc_or_end(N * sizeof(int));
/* initialize rootWord and occurrences for the "each word is unique and occurs only once" scenario */
for(i = 0; i < N; i++) {
uniqueWords[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char));
occurrences[i] = 1;
}
determineUniqueWords(occurrences,wordList,N);
/* populate the wordCounts & uniqueWords "arrays" with the appropriate data in order to sort them successfully */
for(i = 0; i < N; i++) {
if(occurrences[i] > 0) {
wordCounts[i] = count(N,wordList[i],1);
uniqueWords[i] = wordList[i];
}
}
for(i = 0; i < N; i++) {
free(uniqueWords[i]);
}
free(uniqueWords);
free(occurrences);
free(wordCounts);
return;
}
int main(int argc,char *argv[]) { /* argv[1] = op argv[2] = name argv[3] = <word> */
int N = -1;
int i = 0;
int spaceNum,nlNum = -1;
file = fopen(argv[2],"r");
if(file == (FILE *) NULL) { /* check if the file opened successfully */
fprintf(stderr,"Cannot open file\n");
}
fscanf(file,"%d",&N); /* get the N number */
wordList = malloc_or_end(N * sizeof(char *)); /* allocate memory for pointers */
for(i = 0; i < N; i++) {
wordList[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char)); /* allocate memory for strings */
}
populateWordsArray(N);
if(strcmp(argv[1],"-reverse") == 0) {
reverse(N);
} else if(strcmp(argv[1],"-first") == 0) {
first(N);
} else if(strcmp(argv[1],"-middle") == 0) {
middle(N);
} else if(strcmp(argv[1],"-last") == 0) {
last(N);
} else if((strcmp(argv[1],"-count") == 0) && argv[3] != NULL) {
i = count(N,argv[3],0);
} else if((strcmp(argv[1],"-sorted") == 0) && (strcmp(argv[3],"-count") == 0)) {
sortedCount(N);
} else {
/* i only wish i could print something here */
}
/* End of program operations */
for(i = 0; i < N; i++) {
free(wordList[i]);
}
free(wordList);
fclose(file);
return 0;
}
You are overwriting the value of a pointer to heap memory on line 185:
uniqueWords[i] = wordList[i];
This means that when you free it later, you are actually freeing the allocated rows in wordList. Now you have two problems:
When you free the wordList rows on lines 244-246, it will be a double-free
You are losing your reference to the uniqueWords rows.
Use strcpy to assign to a dynamically-allocated string rather than the = operation.
I'm working on a project and I'm kinda stuck at a problem. I'm trying to read a file that contains a number in the first line that gives the number of rows, and then following the matrix of integers, separated by spaces.
I want to make a pointer in the main, then call the function with the pointer as parameter, the function should read the first number in the txt file, then create a 2d array with malloc, then read the matrix in the textfile and return.
but either i get it so the function can allocate and read the matrix, but then i have something wrong with the pointer when calling the function so i cant use the allocated and read stuff in the main, or im getting errors when trying to call by reference and allocate stuff in the function then.
void readjobs(FILE* fp, int ***array, int linesToRead, int facilityCount) {
int ch = 0;
int rows = 0;
while ((ch = fgetc(fp)) != '\n')
{
rows = ch - 48;
//rows = rows * 10 + (ch - 48);
}
if (rows > linesToRead) rows = linesToRead;
*array = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
/* size_y is the height */
*array[i] = (int*)malloc(facilityCount * sizeof(int));
}
int i = 0, j = 0;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
{
i++;
printf("\n");
}
else if (ch == ' ')
{
j++;
printf("%i ", *array[i][j]);
}
else //wenn es ne nummer ist
{
*array[i][j] = (*array[i][j] * 10) + (ch - 48);
}
}
}
int main(int argc, char** argv) {
int facilities_count = -1;
int jobs_count = -1;
int **jobs = NULL;
FILE *fp; //Zeiger für Datei
fp = fopen("jobs.txt", "r"); //Dateizugriff, Datei als read
if (fp == NULL) { //falls die Datei nicht geoeffnet werden kann
printf("Datei konnte nicht geoeffnet werden!!\n");
}
else { //Datei konnte geoeffnet werden
printf("Datei ist lesbar\n");
readjobs(fp, &jobs, 6, 6);
if (jobs == NULL)printf("nullpionter");
else {
for (int i = 0; i < 6; i++) {
printf("\n");
for (int j = 0; j < 6; j++) {
printf("%x ", jobs[i][j]);
}
}
}
fclose(fp); //Dateizugriff wieder freigeben
}
MPI_Finalize();
getchar();
return 0;
}
Textfile example:
6
3 2 2 1 5 4
1 1 3 4 2 0
1 2 3 4 5 1
3 4 2 0 1 5
1 0 5 2 3 4
4 0 1 3 5 2
the first number "6" in this case is how many lines, and the rest is the matrix to be read
Your main problem
I compiled your code with debugging on:
$ cc -g mat.c -Wall -Wextra
Ran it in debugger:
$ gdb a.out
(gdb) run
Starting program: /tmp/a.out
Datei ist lesbar
Program received signal SIGSEGV, Segmentation fault.
0x00005555555548ff in readjobs (fp=0x555555756010, array=0x7fffffffe740, linesToRead=6, facilityCount=6)
at mat.c:18
18 *array[i] = (int*)malloc(facilityCount * sizeof(int));
Ok, so it crashes at this line:
*array[i] = (int*)malloc(facilityCount * sizeof(int));
Doing so is always a good idea to find out what the problem is. What could be the cause? Unfortunately it is not trivial in this case. Unless you really understand pointers. *array[i] is not what you want. You want (*array)[i].
Remember that x[i] is just a shortcut for *(x+i). Furthermore, [] has higher priority than *. So *x[i] = *(x[i]) = *(*(x+i)), but what you want is (*x)[i] = *((*x) + i) which clearly is not the same thing.
Other stuff
I would definitely extract the creation of the matrix, like this:
int ** createMatrix(int rows, int columns) {
printf("%d %d\n", rows, columns);
int **ret;
ret = malloc(rows * sizeof *ret);
if(!ret) { perror("Error: "); exit(EXIT_FAILURE); }
for(int i=0; i<columns; i++) {
ret[i] = malloc(columns * sizeof (*ret)[0]);
if(!ret[i]) { perror("Error: "); exit(EXIT_FAILURE); }
}
return ret;
}
and then in your code:
*array = createMatrix(rows, facilityCount);
// Don't trust my code. Check the pointer.
if(!array) { perror("Error: "); exit(EXIT_FAILURE); }
Remember to ALWAYS check if malloc succeeded.
And your way of reading the numbers is very weird. If you are a beginner who came up with this method on your own, that's actually pretty impressive, but it's not a good method. Read about fscanf and getline.
Consider the following functions
void alloco(int **ppa)
{
int i;
printf("inside alloco %d\n",ppa); /*this function allocates and fills 20 * sizeof(int) bytes */
*ppa = (int *)malloc(20 * sizeof(int));
/*fill all 20 * sizeof(int) bytes */
}
int main()
{
int *app = NULL;
int i;
printf("inside main\n");
alloco(&app);
for(i=0;i<20;i++) /*ISSUE::how will i know to traverse only 20 indexes?*/
printf("app[%d] = %d \n", i, app[i]);
return(0);
}
Basically how will main() come to know number of bytes to traverse i.e memory allocated by alloco() function. Is there any delimiter like NULL in character arrays?
That is not possible, you need to keep that value somewhere, for example you could do this,
void alloco(int **ppa, int count)
{
int i;
printf("inside alloco %d\n",ppa);
*ppa = malloc(count * sizeof(int));
if (*ppa == NULL)
return;
for (i = 0 ; i < count ; ++i)
/* fill it here. */
}
int main()
{
int *app;
int i;
int count;
count = 20;
app = NULL;
printf("Inside main\n");
alloco(&app, count);
if (app == NULL)
return -1;
for (i = 0 ; i < count ; i++)
printf("app[%d] = %d \n", i, app[i]);
/* done with `app' */
free(app);
return 0;
}
Many other combinations could work, for example
int alloco(int **ppa)
{
int i;
printf("inside alloco %d\n",ppa);
*ppa = malloc(20 * sizeof(int));
if (*ppa == NULL)
return;
for (i = 0 ; i < count ; ++i)
/* fill it here. */
return 20;
}
int main()
{
int *app;
int i;
int count;
printf("Inside main\n");
app = NULL;
count = alloco(&app);
if (app == NULL)
return -1;
for (i = 0 ; i < count ; i++)
printf("app[%d] = %d \n", i, app[i]);
/* done with `app' */
free(app);
return 0;
}
But I personally don't like this because if there is going to be a fixed number of integers it's not a good idea to use malloc() just,
int main()
{
int app[20];
int i;
printf("Inside main\n");
for (i = 0 ; i < sizeof(app) / sizeof(app[0]) ; i++)
printf("app[%d] = %d \n", i, app[i]);
return 0;
}
Is there any delimiter like NULL in character arrays?
If you define one, yes.
This however only is possible if your use case does not need all possible integer values.
If for example you would only need positive values including 0 you can define the value of -1 to be the "End-of-Array" marker.
You then would allocate one more element to the array then you need and assign -1 to this additional very last array element.
Example:
#include <stdlib.h> /* for malloc */
#include <errno.h> /* for errno */
#define EOA (-1)
int array_allocate(int ** ppi)
{
int result = 0;
if (NULL = ppi)
{
result = -1;
errno = EINVAL;
}
else
{
size_t number_of_elements = ...; /* Assign some positive value here. */
*ppi = malloc((number_of_elements + 1) * sizeof ** ppi);
if (NULL == *ppi)
{
result = -1;
}
else
{
(*ppi)[number_of_elements] = EOA;
}
}
return result;
}
ssize_t array_number_of_elements(int * pi)
{
int result = 0;
if (NULL == pi)
{
result = -1;
errno = EINVAL;
}
else
{
int * pi_tmp = pi;
while (EOA != *pi_tmp)
{
++pi_tmp;
}
result = pi_tmp - pi;
}
return result;
}
Use it like this:
#include <stdlib.h> /* for size_t and ssize_t */
#include <stdio.h> /* for printf and perror */
int array_allocate(int **);
ssize_t array_number_of_elements(int *);
int main(void)
{
int result = EXIT_SUCCESS;
int * pi = NULL;
if (-1 == array_allocate(&pi))
{
result = EXIT_FAILURE;
perror("array_allocate() failed");
}
else
{
ssize_t result_number_of_elements = array_number_of_elements(pi);
if (-1 == result_number_of_elements)
{
result = EXIT_FAILURE;
perror("array_number_of_elements() failed");
}
else
{
size_t number_of_elements = result_number_of_elements;
printf("The number of array's elements is %zu.\n",
number_of_elements);
}
}
free(pi); /* Clean up. */
return result;
}
It takes becoming a 3-Star Programmer
You can easily allocate some fixed number of elements (less than the maximum) in an function without passing the number of elements between the caller function and the callee. However, it takes creating an array of pointers to pointers to type How/Why? Essentially, you are treating your array as a null-terminated string, initially allocating all pointers to type within the array to NULL and only allocating space for them as needed. (allocating with calloc makes this a snap) When the array is used back in the caller, it allows iterating over all filled values until your reach the first null-pointer.
Now granted,
simply passing a pointer to size as an additional argument to your
function makes much more sense [1]
and eliminates the need for a triple-star rating, but for the purpose of example, enjoy being a 3-Star Programmer for a while:
#include <stdio.h>
#include <stdlib.h>
#define INITSZ 21
void alloco (int ***ppa)
{
printf("inside %s\n", __func__);
int i = 0;
/* allocate 21 pointers-to-int */
if (!(*ppa = calloc (INITSZ, sizeof **ppa))) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
/* allocate/fill 20 values (or anything less than 21) */
for (i = 0; i < INITSZ - 1; i++) {
if (!((*ppa)[i] = calloc (1, sizeof ***ppa))) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
*((*ppa)[i]) = i * 2;
}
}
int main()
{
int **app = NULL;
int i = 0;
printf ("inside main\n");
alloco (&app);
/*ISSUE::how will i know to traverse only 20 indexes?*/
while (app[i]) {
printf("app[%d] = %d \n", i, *(app[i]));
i++;
}
return(0);
}
Use/Output
$ ./bin/alloc_array+1
inside main
inside alloco
app[0] = 0
app[1] = 2
app[2] = 4
app[3] = 6
app[4] = 8
app[5] = 10
app[6] = 12
app[7] = 14
app[8] = 16
app[9] = 18
app[10] = 20
app[11] = 22
app[12] = 24
app[13] = 26
app[14] = 28
app[15] = 30
app[16] = 32
app[17] = 34
app[18] = 36
app[19] = 38
footnote [1]: emphasis added to the quote for clarity that this solution was intended to show what was possible, not what was most efficient or most practical.