This question already has answers here:
How C strings are allocated in memory?
(5 answers)
Closed 8 years ago.
I want to make dynamically allocated c-string table, but I think i don't understand the topic very well, could You explain it to me or correct my code?
#include <stdio.h>
int main()
{
int i;
char** t;
t=(char**)malloc(16*sizeof(char*));
for(i<0;i<100;i++)
{
*t[i]=(char*)malloc(16*sizeof(char));
}
return 0;
}
You should use variables for everything you want. For example, you allocate a memory for 16 elements of type char* and, as a result, you have an array with 16 elements, but then you are going from 0 to 100 ? Why ?
#include <stdio.h>
int main()
{
int n = 16;
int m = 16;
// Allocate a memory for n elements of type char*
char** t = (char**)malloc(n * sizeof(char*));
for(int i = 0; i < n; ++i)
{
// For each element in array t - initialize with another array.
// Allocate m elements of type char
t[i] = (char*)malloc(m * sizeof(char));
// Initialize
for(int j = 0; j < m; ++j)
t[i][m] = 'a';
}
// Print
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
printf("%c ", t[i][m]);
printf("\n");
}
// Free allocated memory!
for(int i = 0; i < n; ++i)
free(t[i]);
free(t);
return 0;
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int main(int I__argC, char *I__argV[])
{
int rCode=0;
int i;
char **t=NULL;
size_t arraySize;
/* Parse command line args. */
if(2 != I__argC)
{
rCode=EINVAL;
printf("USAGE: %s {dynamic array size}\n", I__argV[0]);
goto CLEANUP;
}
arraySize=strtoul(I__argV[1], NULL, 0);
if(0 == arraySize)
{
rCode=EINVAL;
fprintf(stderr, "Cannot allocate a dynamic array of size zero.\n");
goto CLEANUP;
}
/* Allocate a dynamic array of string pointers. */
errno=0;
t = malloc(arraySize * sizeof(*t));
if(NULL == t)
{
rCode = errno ? errno : ENOMEM;
fprintf(stderr, "malloc() failed.\n");
goto CLEANUP;
}
memset(t, 0, arraySize * sizeof(*t));
/* Initialize each pointer with a dynamically allocated string. */
for(i=0; i<arraySize; i++)
{
errno=0;
t[i]=strdup("A string");
if(NULL == t[i])
{
rCode= errno ? errno : ENOMEM;
fprintf(stderr, "strdup() failed.\n");
goto CLEANUP;
}
}
CLEANUP:
/* Free the array of pointers, and all dynamically allocated strings. */
if(t)
{
for(i=0; i<arraySize; i++)
{
if(t[i])
free(t[i]);
}
free(t);
}
return(rCode);
}
Your code can be corrected so that it can create 100X16 character table or table with 100 string of 16 char length.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int noOfStrings = 100;
int eachStringLenght = 16;
char** t;
t=(char**)malloc(noOfStrings*sizeof(char*));
for(i=0;i<noOfStrings;i++)
{
t[i]=(char*)malloc(eachStringLenght*sizeof(char));
}
return 0;
}
Related
Excuse me for the sloppy code, I am still a beginner. But after putting a long time into this programming question I got from my Uni I don't know where to turn.
The question itself is: we need to read from the "staedte.csv" (which displays the population and cities of German states) and then return an array of strings with the strings formatted like this: The city ***** has a population of ****.
You are supposed to pass in 2 arguments into the cli: the number 100 and the state you want to check the cities and population for: example Bayern (Bavaria).
My plan was to make a 2d array. First I would dynamically allocate the memory for the first one by making a for loop and iterating over the original csv to check how many states in the csv = the state from the arguments. Then I would make a dynamic array using the amount of states in the csv matching. Then I would iterate (with for loop) over the list of matching states and then first check the length of the formatted string then: The city ***** has a population of ****., then allocate that memory and store the pointer to that info in the previously created array. Then I try to print the first item of that array, meaning the pointer.
I checked and there are 8 elements in the csv with Bavaria as their state, but in the for loop
for (j = 0; j < 8; j++)
if j is larger than 4 then I Get a segmentation fault even though the space is supposed to be allocated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input3.h"
/* Die Konstanten:
* int MAX_LAENGE_STR - die maximale String Länge
* int MAX_LAENGE_ARR - die maximale Array Länge
* sind input3.c auf jeweils 255 und 100 definiert
*/
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Aufruf: %s <anzahl> <bundesland>\n", argv[0]);
printf("Beispiel: %s 100 Bayern\n", argv[0]);
printf("Klein-/Großschreibung beachten!\n");
exit(1);
}
// int anzahl = atoi(argv[1]);
char *bundesland = argv[2];
// Statisch allokierter Speicher
char staedte[MAX_LAENGE_ARR][MAX_LAENGE_STR];
char laender[MAX_LAENGE_ARR][MAX_LAENGE_STR];
int bewohner[MAX_LAENGE_ARR];
read_file("staedte.csv", staedte, laender, bewohner);
// printf("%s %s", bundesland, laender[5]);
int CityCounter = 0;
int CopyCounter = 0;
int *CityArray;
CityArray = (int *)malloc(0);
for (int i = 0; i < MAX_LAENGE_ARR; i++)
{
if (strncmp(laender[i], bundesland, strnlen(bundesland, 10)) == 0)
{
CityArray = realloc(CityArray, sizeof(CityArray) + sizeof(int) * 1);
CityArray[CityCounter] = i;
CityCounter++;
}
}
// printf("%d", CityCounter);
char **string = (char **)malloc(CityCounter * sizeof(int));
int j;
printf("%d", (int)sizeof(CityArray));
int numOfCities = (int)sizeof(CityArray);
for (j = 0; j < 8; j++)
{
char buffer[100];
size_t size = snprintf(buffer, 50, "Die Stadt %s hat %d Einwohner.\n", staedte[CityArray[j]], bewohner[CityArray[j]]);
string[j] = malloc(sizeof(char) * size);
// string[j][size] = "\0";
strncpy(string[j], buffer, size);
}
// printf("%s", string[2]);
for (int i = 0; i < numOfCities; i++)
{
printf("%s", string[i]);
}
// write_file(string, sizeof(string));
free(string);
}
this is the code I wrote.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "input3.h"
int MAX_LAENGE_STR = 255;
int MAX_LAENGE_ARR = 100;
void write_file(char *result[], int len)
{
FILE *fp = fopen("resultat.txt", "w");
if (fp == NULL)
{
perror("resultat.txt");
exit(1);
}
for (int i = 0; i < len; i++)
{
fprintf(fp, "%s\n", result[i]);
}
fclose(fp);
}
int read_file(char *dateiname, char staedte[][MAX_LAENGE_STR], char laender[][MAX_LAENGE_STR], int bewohner[])
{
FILE *fp = fopen(dateiname, "r");
if (fp == NULL)
{
perror(dateiname);
exit(1);
}
char stadt[MAX_LAENGE_STR];
char land[MAX_LAENGE_STR];
int anzahl;
int i = 0;
int len;
while (fscanf(fp, "\"%[^\"]\";\"%[^\"]\";%d\n", stadt, land, &anzahl) != EOF)
{
if (i >= MAX_LAENGE_ARR)
{
printf("ERROR: Die Datei ist größer als erwartet!");
return i;
}
len = strlen(stadt) + 1;
strncpy(staedte[i], stadt, len - 1);
staedte[i][len - 1] = '\0';
len = strlen(land) + 1;
strncpy(laender[i], land, len - 1);
laender[i][len - 1] = '\0';
bewohner[i] = anzahl;
i++;
}
fclose(fp);
return i;
}
extern int MAX_LAENGE_ARR;
extern int MAX_LAENGE_STR;
void write_file(char *result[], int len);
int read_file(char *dateiname, char staedte[][MAX_LAENGE_STR], char laender[][MAX_LAENGE_STR], int bewohner []);
This code was supplied by our Uni but it should be correct.
So I changed the
char **string = (char **)malloc(CityCounter * sizeof(int)); to char
**string = (char *)malloc(CityCounter * sizeof(char)); and now I don't get null.
But if I once again change the
for (j = 0; j < 4; j++) {}
and modify the j larger then 4 then I get a bus error
I'm trying to build in C an array of structures without defining the length of the maximum size of the array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct text {
char *final;
} text;
int main() {
int n, sizearray = 10, i;
char *str;
text *testo;
testo = (text *)malloc(sizeof(text) * sizearray);
fgets(str, 1024, stdin);
i = 0;
while (str[0] != 'q') {
if (i == sizearray - 1) {
testo = (text *)realloc(testo, sizearray * 2 * sizeof(text));
}
n = strlen(str);
n = n + 1;
testo[i].finale = (char *)malloc(sizeof(char) * n);
strcpy(testo[i].finale, str);
i++;
fgets(str, 1024, stdin);
}
for (i = 0; i < sizearray; i++)
printf("%s \n", testo[i].finale);
return 0;
}
this gives me
process finished with exit code 139 (interrupted by signal 11:SIGSEV).
What am I doing wrong?
There are multiple issues in your code:
[major] str is an uninitialized pointer. You should make it an array of char defined with char str[1024].
[major] you do not adjust sizearray when you double the size of the array, hence you will never reallocate the array after the initial attempt at i = 9.
[major] the final loop goes to sizearray but there are potentially many uninitialized entries at the end of the array. You should stop at the last entry stored into the array.
you should also check the return value of fgets() to avoid an infinite loop upon premature end of file.
you should test for potential memory allocation failures to avoid undefined behavior.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct text {
char *finale;
} text;
int main() {
char str[1024];
text *testo = NULL;
size_t sizearray = 0;
size_t i, n = 0;
while (fgets(str, sizeof str, stdin) && *str != 'q') {
if (n == sizearray) {
/* increase the size of the array by the golden ratio */
sizearray += sizearray / 2 + sizearray / 8 + 10;
testo = realloc(testo, sizearray * sizeof(text));
if (testo == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}
}
testo[n].finale = strdup(str);
if (testo[n].finale == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}
n++;
}
for (i = 0; i < n; i++) {
printf("%s", testo[i].finale);
}
for (i = 0; i < n; i++) {
free(testo[i].finale);
}
free(testo);
return 0;
}
str is uninitialized. Either allocate memory with malloc or define it as an array with char str[1024].
Currently, I am trying to create a C program that prints the last few lines of a text file, read in through the command line. However, it is currently causing a segmentation error when I try to copy the strings from fgets into the main array. I have been unable to fix this, and so have not been able to test the rest of my code. How would I begin to fix the segmentation error? I have posted the code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1,j,printNumber;
char **arr = (char **) malloc (100 * sizeof(char *));
char *line = (char *) malloc (80 * sizeof(char));
if (argc == 1) {
printNumber = 10;
}
else {
printNumber = atoi(argv[1]);
}
while (fgets(line,80,stdin) != NULL) {
if (line != NULL) {
line[strlen(line)-1] = '\0';
strcpy(arr[i],line); //SEGMENTATION ERROR!!!!
}
else {
free(line);
strcpy(arr[i],NULL);
}
i++;
printf("%d ",i);
}
free(arr);
for (j = i-printNumber-1; j < i-1; j++) {
printf("%s ", arr[j]);
}
printf("\n");
return 0;
}
You are allocating space for arr, which is a pointer to a pointer to char, but not allocating any individual char * pointers within arr.
Since you allocated arr with the size of 100 * sizeof(char *), I assume you want 100 sub-entries in arr. Sure:
for(i = 0; i < 100; i++)
arr[i] = malloc(80 * sizeof(char));
Then, when you free arr:
for(i = 0; i < 100; i++)
free(arr[i]);
free(arr);
Note that it is good practice to always check malloc for failure (return value of NULL) and handle it, and to set pointers to NULL after freeing them once to avoid double-free bugs.
You don't always know the length of the longest line (not until you try to read) OR how many last lines you are expected to keep track of (but is given at runtime). Thus, both of these values need to be known before you allocate memory or delegated to a function that does it for you.
#include <stdio.h>
#include <stdlib.h>
struct Line {
char *line; // content
size_t storage_sz; // allocation size of line memory
ssize_t sz; // size of line, not including terminating null byte ('\0')
};
int main(int argc, char *argv[]) {
int max_lines = 10;
if (argc > 1) {
max_lines = atoi(argv[1]);
}
if (max_lines < 0) {
fprintf(stderr, "%s\n", "Sorry, no defined behaviour of negative values (yet)\n");
return EXIT_FAILURE;
}
// keep an extra slot for the last failed read at EOF
struct Line *lines = (struct Line *) calloc(max_lines + 1, sizeof(struct Line));
int end = 0;
int size = 0;
// only keep track of the last couple of lines
while ((lines[end].sz = getline(&lines[end].line, &lines[end].storage_sz, stdin)) != -1) {
end++;
if (end > max_lines) {
end = 0;
}
if (size < max_lines) {
size++;
}
}
// time to print them back
int first = end - size;
if (first < 0) {
first += size + 1;
}
for (int count = size; count; count--) {
// lines might contain null bytes we can't use printf("%s", lines[first].line);
fwrite(lines[first].line, lines[first].sz, 1u, stdout);
first++;
if (first > size) {
first = 0;
}
}
// clear up memory after use
for (int idx = 0; idx <= max_lines; idx++) {
free(lines[idx].line);
}
free(lines);
return EXIT_SUCCESS;
}
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.
I'm using a dynamic array of strings in C:
char** strings;
I initialize it:
int max = 10;
strings = malloc(sizeof(char*) * max);
And copy a couple of dummy strings:
char* str = "dummy";
for (int i = 0; i < max; i++) {
strings[i] = malloc(strlen(str) + 1);
strncpy(strings[i], str, strlen(str) + 1);
}
Yet when I try to print this:
for (int i = 0; i < max; i++)
printf("array = %s", strings[i])
I get this error from Splint:
Value strings[] used before definition
An rvalue is used that may not be initialized to a value on some execution
path. (Use -usedef to inhibit warning)
Checking for NULL like this will not help:
for (int i = 0; i < max; i++)
if (strings[i] != NULL)
printf("array = %s", strings[i])
since strings[i] is still used "before definition".
Any ideas on how to solve this?
Edit: Will try this with a linked list instead, I think.
Also, complete code listing:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char** strings;
int i;
int max = 10;
char* str = "hello";
// Dynamic array with size max
strings = malloc(sizeof(char*) * max);
// Abort if NULL
if (strings == NULL)
return (-1);
// Define strings
for (i = 0; i < max; i++)
{
strings[i] = malloc(strlen(str) + 1);
// Abort if NULL
if (strings[i] == NULL)
{
// Undetected memory leak here!
free(strings);
return (-1);
}
strncpy(strings[i], str, strlen(str) + 1);
}
// Print strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
printf("string[%d] = %s\n", i, strings[i]);
}
// Free strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
free(strings[i]);
}
free(strings);
return 0;
}
I do not have Splint on my machine, so i cannot test with it, just an another way to your task:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int i, len, max;
char* str = "hello";
len = strlen(str) + 1;
max = 10;
char strings[max][len];
for (i = 0; i < max; i++) {
strcpy(strings[i], str);
}
for (i = 0; i < max; i++) {
printf("string[%d] = %s\n", i, strings[i]);
}
return 0;
}
Avoid creating non-continuous memory it would be better approach if you allocate memory in single malloc call.
Memory can be freed in single free call instead of multiple free call
max_rows * sizeof(char) will allocate 2 * 1
((strlen(str) * N) + 1) will allocate memory for every N element.
Here is my approch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
size_t max_rows = 2;
char* str = "dummpy";
char* vec_s = (char *) malloc( max_rows * sizeof(char) * ((strlen(str) * max_rows) + 1));
for (int i = 0; i < max_rows; i++){
strcpy((vec_s + i), str);
printf("vec_s[%d]=%s\n", i, (vec_s + i));
}
free(vec_s);
return 0;
}