My array is being overwritten with the same values? - c

so I have an array that keeps getting overwritten with new values. For example, this is the output:
instruc[0] = PRINTNUM
instruc[1] = PRINTNUM
instruc[2] = PRINTNUM
where PRINTNUM is supposed to be the last thing in the array and the first two elements are supposed to be something else.
Here is my code for the specific segment:
//array of instructions
char** instruc = malloc(numLines * 200);
c = fgets(inputString, 200, in_file);
while (c != NULL){
instruc[i]=inputString;
i++;
c = fgets(inputString, 200, in_file);
}
//print out what's in the array
i=0;
for (i=0; i<numLines; i++){
printf("instruc[%d] = %s\n", i, instruc[i]);
}
Thanks in advance!

There is no memory allocated to store the lines read in from the file. Yes there is memory allocated but instruc is of type char ** and the program is using this memory as if instruc is of char * type.
If you wish to store the pointers to all the records in the file memory must be allocated not only to store the data in the file BUT also memory is required to store the pointers to the start of each record.
In this code it appears the file records are fixed length 200 bytes long. The array of pointers which a variable of char ** would point to is not strictly necessary - it would be possible to determine the start of the next record simply by adding 200 bytes to the char * pointer to the start of the data read from the file.
To store the pointers to the start of each record something like this would be required-:
char **fileRecPtrs = malloc(sizeof(char *) * numLines);
char *instruc = malloc(200 * numLines);
Then in the loop to read each record of the file-:
c = fgets(instruc, 200, in_file);
while (c != NULL) {
fileRecPtrs[i] = instruc;
instruc += 200;
i++;
c = fgets(instruc, 200, in_file);
}

You're pointing every index in the array to the same memory address. I think you'd be better off using strcpy

Related

Segmentation fault when trying to access properly allocated array

I'm trying to read a CSV file and am writing a function to parse a line of data into an array of strings, which dynamically changes the size of the array and updates size and str_size accordingly. I have written a properly-working function called find_key() to locate the fseek() location of the line in question. I'm coming across a problem that I think relates to the allocation of the string array: I get a segmentation fault on the line at the bottom of the while loop, where it reads data[data_count][str_pos] = curr. The program breaks when I try to access data[0][0], even though as far as I can tell I've allocated memory properly. Any help would be appreciated!
/**
* #brief Get a row from the provided CSV file by first item. Dynamically
* allocated memory to data array
*
* #param file
* #param key First item of row
* #param data Array of strings containing data
* #param size Size of array
* #param str_size Size of strings in array
* #return 0 if successful, -1 if the row cannot be found, or 1 otherwise
*/
int csv_get_row(FILE *file, char *key, char **data, size_t *size, size_t *str_size) {
if(!file || !key) return 1;
/* Get the position of the beginning of the line starting with the key */
long pos = find_key(file, key);
if(pos == -1) return -1;
fseek(file, pos, SEEK_SET);
/* If these parameters aren't useful values, assign default values */
if(*size < 1) *size = DEFAULT_ARRAY_SIZE;
if(*str_size < 1) *str_size = DEFAULT_BUFFER_SIZE;
/* If the memory for the array hasn't been allocated, do so now */
if(!data) data = (char**) malloc(*size * *str_size);
/* Get characters one-by-one, keeping track of the current amount of elements and the current buffer position */
size_t data_count = 0;
size_t str_pos = 0;
char curr;
while(fscanf(file, "%c", &curr)) {
if(data_count >= *size) data = (char**) realloc(data, (*size *= 2) * *str_size);
if(str_pos >= *str_size) data = (char**) realloc(data, *size * (*str_size *= 2));
if(curr == ',') {
data[data_count][str_pos] = '\0';
data_count++;
str_pos = 0;
continue;
}
if(curr == '\n') {
data[data_count][str_pos] = '\0';
data_count++;
break;
}
data[data_count][str_pos] = curr;
str_pos++;
}
/* Resize the array to fit */
*size = data_count;
data = (char**) realloc(data, *size * *str_size);
return 0;
}
Assume that *size starts at 1. You set data_count to 0. Then, in the first iteration,
you do not have data_count >= *size, so you don't realloc(). You increment data_count
to 1, though, so in the next iteration, you grow the data buffer to 2.
So, at this point, data has length 2 and data_count is 1.
Let's then say we do not go into the first if statement but the second.
There, you increment data_count to two. You then access data[data_count], which is one
past the last element. That is a problem.
That might be the problem you see at the end of the while-loop, but it is far from the
only problem. Whenever you malloc() or realloc() data, you are invalidating the pointer the caller
has, because you might be freeing the memory at the original location. You never give him
a pointer to the new data back; all the newly allocated data will be leaked when you
return from the function, and the caller must never access data after the call, lest
he wants a segfault.

Save pointer to structure into an array of pointers

I am having a hard time getting an array of pointer to structures to save and retrieve the data I filled, the code snippet has the core of my program.
I was able to make the program itself work using an array of struct, but I figure that is more memory intensive and I am trying to only realloc the array of pointers to the structures instead of all the structs at each loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dados_aluno {
int matricula;
char nome[60];
int situacao;
float nota1, nota2, nota3, media;
}dados_aluno;
int main(void){
int done = 0;
int i;
int n_alunos = 0;
int matricula_atual;
dados_aluno *novo_aluno;
dados_aluno **alunos_da_turma;
alunos_da_turma = malloc(sizeof(dados_aluno*));
while (done == 0){
printf("Matricula: ");
scanf("%d", &matricula_atual);
fflush(stdin);//scanf followed by gets = bad time!
if (matricula_atual == -1){
done = 1;
continue;
}
n_alunos++;
novo_aluno = calloc(1, sizeof(dados_aluno));
novo_aluno->matricula = matricula_atual;
printf("\nNome: ");
gets(novo_aluno->nome);
//the code below rises warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
//and returns garbage on the for loop at the end of the program
alunos_da_turma[n_alunos - 1] = &novo_aluno;
//using memcpy instead doesnt rise an error, but the first field is garbage and the 3º interation of the loop crashes
//memcpy(alunos_da_turma[n_alunos -1],&novo_aluno,sizeof(dados_aluno *));
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
}
for (i=0;i<(n_alunos);i++){
printf("%d %s\n",alunos_da_turma[i]->matricula,alunos_da_turma[i]->nome);
}
}
I expect to dynamic allocate a struct "dados_alunos" and also dynamic allocate an array of pointers to said structs, insert user input "nome" and "matricula_atual" to the fields of the struct "dados_alunos" and be able to read them after exiting the while loop.
On trying to save the address to the current struct to the array using
alunos_da_turma[n_alunos - 1] = &novo_aluno;
gives the warning "assignment from incompatible pointer type [-Wincompatible-pointer-types]" and seems to save to all the positions of the array the first pointer/garbage written to it no matter how many interactions.
Using memcpy instead store garbage on the first field if I only try one interaction and crashes within 2 interactions or more on the while loop.
alunos_da_turma[n_alunos - 1] = &novo_aluno;
is refused because alunos_da_turma is a dados_aluno ** so alunos_da_turma[n_alunos - 1] is a dados_aluno *, but novo_aluno is a dados_aluno * so &novo_aluno is a dados_aluno **
you wanted
alunos_da_turma[n_alunos - 1] = novo_aluno;
Warning
gets(novo_aluno->nome);
is dangerous (and deprecated since years) because if the input string is greater than 59 characters you write out of the field with an unexpected behavior, do
fgets(novo_aluno->nome, sizeof(novo_aluno->nome), stdin);
However except if you enter the name on the same line you enter the matricula you will get an empty line because the rest of the line/newline is not flush by fflush(stdin);, fflush does not work out of a file
If the name cannot contain separator use scanf("%59s", novo_aluno->nome); rather than fgets, else bypass characters up to the newline explicitely
Note also in
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
you reallocate with one extra element, you already increased n_alunos
Doing
int done = 0;
...
while (done == 0){
...
if (matricula_atual == -1){
done = 1;
continue;
}
...
}
is quite complicated for nothing and can be replaced by
for (;;) {
...
if (matricula_atual == -1)
break;
...
}
alunos_da_turma[X] is a pointer to struct dados_aluno, not a pointer to a pointer to a struct dados_aluno.
What would be valid is alunos_da_turma[n_alunos-1] = novo_aluno
So, some solution for general problem:
dados_alunos** alunos_da_turma = malloc (10 * sizeof(dados_aluno*)); //array for 10 pointers
int length = 0; //number of inserted alunos_dados elements
int size = 10; //number of allocated pointers spaces
while(done == 0){
//ask for input
dados_aluno* novo_aluno = malloc (sizeof(dados_aluno));
novo_aluno->matricula = //input
//etc
dados_alunos[length] = novo_aluno;
length++;
if (length == size){
dados_alunos = realloc(dados_alunos, 2 * size * sizeof(dados_aluno*));
size += size; //doubles size
}
}

C programming, losing data after realloc

I am trying to get string of numbers and put it inside an int array.
I have no idea how many numbers I am going to get so I need to use dynamic allocation.
I created an array by using malloc and tried to resize it by +1 every time inside the loop.
This is my code
void main()
{
char *s;
int *polyNums;
int count = 0;
char *token;
s = gets();
polyNums = (int *)malloc(sizeof(int));
if (polyNums == NULL)
{
printf("Could not allocate required memory\n");
exit(1);
}
token = strtok(s, " ");
while (token != NULL)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1);
token = strtok(NULL, " ");
}
}
My problem is that every time it's doing realloc, all the saved numbers are gone, if my string is "1 2 3" so in loop 1 the polyNums[0] is 1, but I am loosing it in loop 2 after reallocating. Can some one please tell me where I went wrong?
You do not allocate enough memory for your array.
int *polyNums; // Holding integer!
int count = 0;
polyNums = (int *)malloc(sizeof(int)); // enough space for interger. OK!
...
while(...)
{
polyNums[count] = *token - '0';
count++;
polyNums = realloc(polyNums, count+1); // Not enough space for intergers!
...
}
You access an array holding int values but you only allocate 1 byte per element.
While your first allocation can hold the first integer, you allocate less memory for any forther number.
polyNums = realloc(polyNums, (count+1)*sizeof(*polyNums));
Aside from that:
Do not cast the return value of malloc
Do not assign the return value of realloc directly to your pointer. In case of NULL return value you lose your old data.
You should take a look at pointers and resource management, more specifically you should learn what deep copy is and how to reallocate dynamic memory.
In general, you should define a temporary pointer for the new larger chunk of memory, copy all the old values to the new memory location and then you can reassign the temporary pointer to the initial pointer, polyNums. Then you are safe to add more new data.

Allocation memory error with use struct for c

I wrote a code for managing a library; the compilation is done but during the simulation I obtained an Allocation error (case2) and I don't know why.
The first case works correctly but if I entered more than one name in the first case, the second case doesn't work.
What did I do wrong? I hope I was clear enough.
typedef struct {
char name[80];
char **books;
int books_num;
} Subscription;
int main() {
// Variables declaration:
int option = 0, subs_num = 0, i = 0, books_num = 0;
Subscription *subs_library;
char **books;
char subs_new_name[80], book_new_name[80];
printf("Choose an option\n");
do {
scanf("%d", &option);
switch (option) {
case 1:
printf("Case 1: enter a new name\n");
scanf("%s", subs_new_name);
if (subs_num == 0) {
subs_library = malloc(sizeof(Subscription));
} else {
subs_library = realloc(subs_library, sizeof(Subscription));
}
strcpy(subs_library[subs_num].name, subs_new_name);
subs_library[subs_num].books_num = 0;
subs_num++;
printf("ADDED\n");
break;
case 2:
printf("Case 2: enter the book name\n");
scanf("%s", book_new_name);
if (books_num == 0) {
books = malloc(sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
} else {
books = realloc(books, sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
}
if (books[books_num] == NULL) {
printf("Allocation Error\n");
exit(1);
}
strcpy(books[books_num], book_new_name);
books_num++;
printf("ADDED\n");
break;
}
} while (option != 7);
return 0;
}
Your code to reallocate the arrays is incorrect. You do not allocate enough room for the new array sizes. When you reallocate these arrays, you pass the size of a single element, therefore the array still has a length of 1 instead of subs_num + 1. The size passed to realloc should be the number of elements times the size of a single element in bytes.
Initialize subs_library and books to NULL and change your array reallocations:
if (subs_num == 0) {
subs_library = malloc(sizeof(Subscription));
} else {
subs_library = realloc(subs_library, sizeof(Subscription));
}
Into this:
subs_library = realloc(subs_library, (subs_num + 1) * sizeof(*subs_library));
And do the same for books, change:
if (books_num == 0) {
books = malloc(sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
} else {
books = realloc(books, sizeof(char*));
books[books_num] = malloc(80 * sizeof(char));
}
To this:
books = realloc(books, (books_num + 1) * sizeof(*books));
books[books_num] = malloc(80 * sizeof(char));
Or simpler:
books = realloc(books, (books_num + 1) * sizeof(*books));
books[books_num] = strdup(book_new_name);
I guess the problem is with scanf reading a string only until a separator, in your case - a whitespace separating multiple names entered. The characters after separator remain in the input buffer and get immediately processed by other calls to scanf.
You should consider using getline for reading name(s) and checking return values from other calls to scanf.
The problem is your reallocation calls. For example you do
realloc(books,sizeof(char*))
This reallocates the memory pointed to be books to be one pointer to character in size, which is exactly what you already have. This will lead you to index out of bounds of the allocated memory, something which is undefined behavior.
If you want to allocate more than one element you need to multiply the base type size with the number of elements you want to allocate, e.g.
realloc(books, (books_num + 1) * sizeof(char *))
Your reallocation realloc(books, sizeof(char *)) only allocates the size of one pointer char *, not the size of the enlarged array that you need:
books=realloc(books,sizeof(char*));
You need to multiply the size of a pointer (char *) by the number of books you plan on storing in the array. You maintain the number of books in books_num.
As Joachim Pileborg said, with every allocation/reallocation, you want this to be one more than the current size. For the first allocation (malloc()), you want to allocate for one book, which is 1 times sizeof(char *). This happens to be equivalent to your existing code, which is fine. But the reallocation (realloc()) reallocates for the same size every time (only enough for one pointer), so you're not enlarging the allocation. You need to multiply the size required for one pointer (sizeof(char *)) by the number of pointers you want, which is books_num + 1. As in Joachim's answer, this is
books = realloc(books, (books_num + 1)*sizeof(char *));
This will enlarge the allocation of the array books by one more pointer. Then, on the next line you correctly allocate a string of size 80.
Your subs_library has the same reallocation issue.
Less frequent reallocation
You might want to resize an allocation less frequently. In this situation, you are reallocating every time you add an entry. One simple technique to reduce the number of reallocations is to double the allocation size every time it gets full. But you have to maintain the allocation size (capacity) and check for it whenever you add something. For example:
char **buffer; /* buffer of pointers to char */
int capacity = 1; /* number of elements allocated for */
int size = 0; /* number of elements actually used */
Then the initial allocation is
/* Initial allocation */
buffer = malloc(capacity*sizeof(*buffer));
And to add some char *new_item to the buffer
/* When adding an element */
if ( size == capacity ) {
/* Double allocation every time */
capacity *= 2;
/* Reallocate the buffer to new capacity */
realloc(buffer, capacity*sizeof(*buffer));
}
/* Item will fit, add to buffer */
buffer[size++] = new_item;
Notice that I have used sizeof(*buffer) instead of sizeof(char *). This makes the compiler figure out what the type and size is. That way, if I change the type of buffer for some reason, I don't have to change more places in the code. Another thing that I left out for brevity is that you should always check the return values to make sure they are not NULL.

Having trouble reading strings from stdin

I need to create program that takes input from stdin in this format:
abcde //number of characters in word = number of words => square shape
fghij
klmno
pqrst
uvwxy
// \n separates first half from second
word1word //any amount of characters, any amount of words
word
word2
sdf
// \n to end input
My code works, but only about 50% of the time. I have couple of example inputs, that I use for testing, but for some of them my readwords function fails.
Here is my function, that reads words. Since I have no idea how many words or how long they are going to be, I use dynamic arrays and getchar() function.
void readWords(char **p,int *n,int w) /* before calling: n = 50; w = 20; p = 50x20 char array */
{
int i = 0,j = 0,x;
char tmp,prevtmp;
while (1)
{
prevtmp = tmp;
tmp = getchar();
if ((prevtmp == '\n' && tmp == '\n') || feof(stdin))
break; /* no more words to read */
if (tmp == '\n') /* end of word */
{
p[i][j] = '\0'; /* add \0 to create string format */
i++;
j = 0;
if (i == *n) /* if there is more words than there is space for them, double the size */
if (realloc(p,*n*2) != NULL)
*n*=2;
continue;
}
p[i][j] = tmp;
j++;
if (j == w) /* if width of word is larger than allocated space, double it */
{
for (x = 0; x < *n;x++);
if(realloc (p[x],w*2) != NULL);
w=w*2;
}
}
*n = i;
}
This is example of input for which this works (note:this function only reads second half after line with only \n):
dsjellivhsanxrr
riemjudhgdffcfz
<skipping>
atnaltapsllcelo
ryedunuhyxhedfy
atlanta
saltlakecity
<skipping 15 words>
hartford
jeffersoncity
And this is input that my function doesn't read properly:
<skipping>
...oywdz.ykasm.pkfwb.zazqy...
....ynu...ftk...zlb...akn....
missouri
delaware
<skipping>
minnesota
southdakota
What my function reads from this input:
e
yoming
xas
florida
lvania
ana
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
There is no difference between those two inputs (except different words and different amount and length of words), the first half gets read properly no matter what, but only the second half bugs out. How do I fix this?
P.S. sorry for long post, in case you want to see full input without skipped bytes, here is pastebin: http://pastebin.com/hBGn2tej
realloc() returns the address of the newly allocated memory, it does not update the argument passed into it. So this (and the other use of realloc()) is incorrect:
if (realloc(p,*n*2) != NULL)
and will results in the code accessing memory incorrectly, causing undefined behaviour. Store the result of realloc() to a temporary variable and check for non-NULL before updating p. The argument to realloc() also indicates the number of bytes, not the number of elements so the size argument calculation is incorrect as p is an array of char* so it should be realloc(p, sizeof(char*) * (*n * 2));. However, the change to p would not be visible to the caller. Also note that the only legal arguments to realloc() are pointers obtained from a previous call to malloc(), realloc() or calloc(). The comment p = 50x20 char array in the code suggests this is not the case.
Here is a small example that allocates an array of char* which should be helpful:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void f(char*** p)
{
/* Allocate space for two 'char*' elements.
Add a NULL pointer element as sentinel value
so caller knows where to find end of list. */
*p = malloc(sizeof(**p) * 3);
/* Allocate space for the two strings
and populate. */
(*p)[0] = malloc(10);
(*p)[1] = malloc(10);
strcpy((*p)[0], "hello");
strcpy((*p)[1], "world");
(*p)[2] = NULL;
/* Add a third string. */
char** tmp = realloc(*p, sizeof(**p) * 4);
if (tmp)
{
*p = tmp;
(*p)[2] = malloc(10);
strcpy((*p)[2], "again");
(*p)[3] = NULL;
}
}
int main()
{
char** word_list = 0;
f(&word_list);
if (word_list)
{
for (int i = 0; word_list[i]; i++)
{
printf("%s\n", word_list[i]);
free(word_list[i]);
}
}
free(word_list);
return 0;
}
Additionally:
prevtmp has an unknown value upon its first use.
getchar() actually returns an int and not a char.

Resources