I'm trying to create an array of strings in C. My plan is for the program to read line from a file and them gradually build this array.
But I noticed that after I allocate memory to this array, some of its indices are 0x0
, and some are trying to access memory in a weird manner. For example:
char** arr_docs = (char**)malloc(sizeof(char*));
In gdb
, I'll try to see the memory addresses of many of this array's indexes:
arr_docs[0]
> 0x0
arr_docs[1]
> 0x0
arr_docs[2]
> 0x0
arr_docs[3]
> 0x1fae1 <error: Cannot access memory at address 0x1fae1>
arr_docs[4]
> 0x0
Wait, what?? Why does arr_docs[3]
is trying to access that address?
I have also noticed that when I'm building the array of strings, the program correctly puts the intended string in arr_docs[0]
, but at some point in the loop (In the debugger, it shows that is when i == 4), arr_docs[0] get allocated again! Here's the for-loop code and the behavior arr_docs[0]
shows in the debugger:
void getlinha(char* buf, FILE* arq){
fgets(buf, 50, arq);
int size = strlen(buf);
// final \n replaced by \0
buf[size-1] = '\0';
}
char* temp = (char*)malloc(sizeof(char));
for(i = 0; i < 6; i++){
//char* temp = (char*)malloc(50);
arr_docs[i] = (char*)malloc(sizeof(char));
getlinha(temp, input);
strcpy(arr_docs[i], temp);
}
In the debugger, when i < 4:
> arr_docs[0]: 0x55555555a530 "sigaa 2"
When i == 4 (More specifically, when arr_docs[4] = (char*)malloc(sizeof(char));
):
> arr_docs[0] : 0x55555555a530 "\260\245UUUU"
I'm completely lost.
Update
Following recommendations, I edited the code. Dumped dynamic memory allocation, since I know how many strings to store. Still, some problems arise. The new code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getlinha(char* buf, FILE* arq){
fgets(buf, 50, arq);
int size = strlen(buf);
// final \n replaced by \0
buf[size-1] = '\0';
}
int main(void){
char* arr_docs[6];
int i;
FILE* input = fopen("file.input", "r");
for(i = 0; i < 6; i++){
getlinha(arr_docs[i], input);
}
}
In this program, fgets
rises Segmentation fault error;
In the debugger, arr_docs[0]
is correctly assigned. But arr_docs[1]
throws the error:
arr_docs[1]
> 0x5555555552bd <__libc_csu_init+77> "H\203\303\001H9\335u\352H\203\304\b[]A\\A]A^A_\303ff.\017\037\204"
fgets(arr_docs[1], 50, input)
> Program received signal SIGSEGV, Segmentation fault.
> __memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:314
Update 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getlinha(char* buf, FILE* arq){
fgets(buf, 50, arq);
int size = strlen(buf);
// final \n replaced by \0
buf[size-1] = '\0';
}
int main(void){
char* arr_docs[6];
int i;
FILE* input = fopen("file.input", "r");
for(i = 0; i < 6; i++){
// assuming the upper bound size of one doc is 50 chars
arr_docs[i] = malloc(50 * sizeof(char));
getlinha(arr_docs[i], input);
}
for(i = 0; i < 6; i++){
free(arr_docs[i]);
arr_docs[i] = NULL;
}
fclose(input);
return 0;
}
There are still some problems in your latest update:
fopen
failure to open the filefgets()
failurefgets()
is longer than 49 bytes including the newline, it will be spill to the next array.strlen(buf)
returns 0.buf
without checking that it is a newline.Here is a modified version without dynamic memory allocation that truncates long lines:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// read a line of input
// return -1 and set buf to the empty string at end of file
// otherwise return the line length
// line read is truncated to fit in buf and null terminated if size>0
// truncation can be detected by testing if the return value >= buffer length.
int getlinha(char *buf, int size, FILE *fp) {
int c, i, j;
for (i = j = 0; (c = getchar()) != EOF && c != '\n'; i++) {
if (i + 1 < size)
buf[j++] = (char)c;
}
if (size > 0)
buf[j] = '\0';
if (i == 0 && c == EOF)
return -1;
return i;
}
int main(void) {
char arr_docs[6][50];
int i, n;
FILE *input = fopen("file.input", "r");
if (input == NULL) {
fprintf(stderr, "cannot open %s: %s\n", "file.input", strerror(errno));
return 1;
}
for (n = 0; n < 6; n++) {
// assuming the upper bound size of one doc is 50 chars
if (getlinha(arr_docs[n], sizeof arr_docs[n], input) < 0)
break;
}
for (i = 0; i < n; i++) {
printf("%d: %s\n", i + 1, arr_docs[i]);
}
fclose(input);
return 0;
}