I need to access a variable length array i have created on the first line reading from a file.
In order to access the array for when i am reading the following lines i would need to initialize it before line 1 is read out side of my conditional statement. but this is before I know the length of the array.
here is an example of my code
int count=0;
while (fgets(line, sizeof(line), fd_in) != NULL) {
if(count==0){
//get wordcount from line
int word[wordcount];
//put line data into array, using strtok()
}else{
//need to access the array here
}
count++;
}
Edit: My question is how should i go about being able to access this array where i need it?
Looks like you want contents of word array to be preserved between loop iterations. This means, you must put the array to the scope outside the loop. In your question code, you want to determine size inside the loop, so you'd essentially need to redefine the size of VLA, which is not possible. You can do this by using malloc as shown in another answer, but looking at your code, it's better to duplicate your call to fgets, allowing you to move the definition of VLA outside your loop, something like:
if(fgets(line, sizeof(line), fd_in) != NULL) {
//get wordcount from line
int word[wordcount];
//put line data into array, using strtok()
int count = 1; // start from 1 per your question code, is it right?
while(fgets(line, sizeof(line), fd_in) != NULL) {
//need to access the array here
count++;
}
}
VLA arrays can't be accesses outside of the scope where they are declared (the scope is inside { } symbols).
So, if your fileformat has the total count in first line, you can use dynamic memory, and malloc your array:
int *words = NULL;
int count=0;
while (fgets(line, sizeof(line), fd_in) != NULL) {
if(count==0){
int wordcount = ... //get wordcount from line
//Allocate the memory for array:
words = (int*) malloc( wordcount * sizeof(int) );
//put line data into array, using strtok()
}else{
//need to access the array here
words[count-1] = ....
}
count++;
}
Related
I want to know how to create a dynamic array of 2 strings per array. And I'm not sure how. I know how to create an array of strings, but not one of "n" dimensions, and i want to know how.
Here are some parts of my code, which is just currently an array of strings:
First I declared my array inside an struct:
typedef struct{
char bloqueCedula[7];
short bloqueDia;
char **bloqueLibrosPrestados;//This is the array i want to modify
}RegistroControl;
then I initialize it on my first registration:
void primerRegistro(RegistroArchivo regArch, RegistroControl *regControl) {
strcpy(regControl->bloqueCedula, regArch.cedula);
regControl->bloqueDia = regArch.dia;
regControl->bloqueLibrosPrestados = malloc(cont * sizeof(regControl->bloqueLibrosPrestados));
regControl->bloqueLibrosPrestados[0] = malloc(7 * sizeof(char));
strcpy(regControl->bloqueLibrosPrestados[0], regArch.codigoLibro);
imprimirCabecera();
//printf("%s\n", regControl->bloqueLibrosPrestados[cont-1]);
}
In the code above I made each string of a length 7, because I already know the length of what I need to copy on it, which is 6.
This is how I kept making it grow:
void procesarRegistro(RegistroArchivo regArch, RegistroControl *regControl) {
cont++;
regControl->bloqueLibrosPrestados = realloc(regControl->bloqueLibrosPrestados,cont * sizeof(regControl->bloqueLibrosPrestados));
regControl->bloqueLibrosPrestados[cont-1] = malloc(7 * sizeof(char));
strcpy(regControl->bloqueLibrosPrestados[cont-1], regArch.codigoLibro);
printf("%s\n", regControl->bloqueLibrosPrestados[cont-2]);
}
I want to know how to add another string of 2 length next to the one that is 7 length. This codes are parts of a code that reads from a file until it reaches EOF, that's why I used a counter which is "cont".
You have a char**.
Suppose a. Allocate some memory to a.
a= malloc(sizeof(char*)*10);
if( a == NULL)
{
fprintf(stderr,"%s","error in malloc");
exit(1);
}
Now for each of the position of a you do the same thing only this time it is for char.
a[i]= malloc(sizeof(char)*100);
if( a[i] == NULL)
{
//...
}
Free them when done.
free(a[i]); //for each i.
free(a);
a=NULL;
Now this is 2 dimension
Now I don't know when you need more than this. This can always be extended.
char *** aa; But it is not needed. {read this}
If you need it then you should think over your data representation.
Theoretical idea for N dimensional strings
For n dimensional you can do this:-
char **...n...** complicated= malloc(sizeof(char**...n...>**)*N1);
// malloc check
for(int i=0;i<N1;i++)
complicated[i]= malloc(sizeof(char**...(n-1)...**)*N2);
...
I have a struct typedef to SmartArray that has a variable char **array. I have been trying to debug the code for several hours, and have made lots of progress. However, i'm stuck on this particular bug. I have a function to print said array out. It will print twice, and then on the third time it does not print at all! I have a feeling this has something to do with how I am adding malloc to an array being one one does not print out correct. For the last section of the array, it prints "Testing Na". Any ideas? I would appreciate the help.
Here is the part of the function I am suspecting is the cause, however, I can't seem to find it: //allocate min space for string
printf("approaching malloc\n");
strPtr = malloc( sizeof(char) * (strlen(str) + 1) );
if(strPtr == NULL)
{
return NULL;
}
printf("made it past malloc!\n");
strcpy(strPtr, str);
//if crash probably this code
smarty->array[index] = strPtr;
if(smarty->array[0] == NULL)
{
return NULL;
}
return strPtr;
Here is my test code:
typedef struct SmartArray
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of array (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} SmartArray;
int main(void)
{
int i; char buffer[32];
SmartArray *smarty1 = createSmartArray(-1);
printf("Array created\n");
// Print the contents of smarty1.
printf("\n-- SMART ARRAY 1: --\n");
printSmartArray(smarty1);
printf("Made it past print!\n");
put(smarty1,"Hi, my name is ");
put(smarty1, "Hello, my name is");
put(smarty1, "Testing Names");
printf("made it past put!\n");
printf("smart away is now\n");
printSmartArray(smarty1);
printf("end of main!\n");
I feel like it's something completely obvious I'm just overlooking because I am a novice.
Here's a picture of what i'm trying to get it to look like in memory:
click here for memory diagram
UPDATE: I figured out why it wasn't printing all the names, but the program segfaults atfter the print function.
I think it is because you are trying to extend your array using malloc. A C array can only point to one block of storage at a time. When you use malloc it will allocate an entirely new block of storage and you are trying to add that on to the end of your array when you write smarty->array[index] = strPtr.
If you want to extend the size of your C array, use realloc instead which will allocate a new, bigger block of memory for your array and copy the existing content to it as well.
If that doesn't solve the problem can you post your entire put function?
Im working on function which reads text file. Function should find out how many records the text file have and malloc an array of structures. It must be array of structures because it is specified in my assignment. LineCounter holds value of how big the array should be. It has value 17 which is correct but when I malloc the array it only have size of 4 structs. I am programming in C and I am also including <stdlib.h> but the compiler is still forcing me to cast malloc.
// SEPARATE HEADER FILE
#pragma once
#define FILECITATEL "citatel.txt" // textovy subor obsahujuci zoznam citatelov
typedef struct Citatel {
int id; // id cislo citatela
char meno[20]; // meno citatela
char priezvisko[30]; // priezvisko citatela
};
Citatel *getReaders();
void printReaders(Citatel *listOfReaders);
// END OF HEADER FILE
Citatel *getReaders() {
FILE *fileRead;
fileRead = fopen(FILECITATEL, "r");
if (fileRead == NULL) {
printf("File cannot be opened!...");
return NULL;
}
char readCharacter;
int lineCounter = 0;
while ((readCharacter = fgetc(fileRead)) != EOF) {
if (readCharacter == '\n') lineCounter++;
}
if (readCharacter == EOF) lineCounter++;
rewind(fileRead);
Citatel *list = (Citatel *)malloc(lineCounter * sizeof(Citatel));
for (int i = 0; i < lineCounter; i++) {
fscanf(fileRead, "%d %s %s", &list[i].id, &list[i].meno, &list[i].priezvisko);
}
printf("%d\n", sizeof list);
fclose(fileRead);
return list;
}
The variable list is a pointer, when you get the size of list you get the size of the pointer and not what it points to. You need to keep track of the memory you allocate yourself.
And the usual link: Don't cast the return of malloc in C (or any other function returning void *).
And if you're programming in C++ then you should be using std::vector instead (or worst case use new[]) and the standard library streams.
You are understanding wrong:
sizeof list
return the size of the pointer not the size of the memory that you allocate.
Your mistake is in the line where you take sizeof list, because that prints the size of list pointer, which is 4 bytes. You want to print lineCounter instead.
Additionally, you are suggested to avoid casting the result of malloc. See here:
Do I cast the result of malloc?
I have my struct, and I have a vector of that struct. Also, I have a .csv file with data separated by comma.
What I need to do is take each value of every line of the .csv file and throw it into my struct vectors. Each line corresponds to a different vector index.
File.csv model
1,carlos,1232
321,patricia,212
5,james riko,23432
The quantity of fields in the same lane may vary, but it will always be separted by comma only.
I did something using strtok() but I couldn't find a way to fill the struct with that.
My Code:
typedef struct{
int num_acc;
char name[25];
double value;
}struct_acc;
int main(){
FILE *arq_acc;
struct_acc acc[3];
char buffer[256];
char *pointer;
arq_acc = fopen("accs.csv", "r");
if(arq_acc == NULL){
printf("Error"); exit(0);}
while(pointer = fgets(buffer, sizeof(buffer), arq_acc) ){
char *token;
while( (token = strtok(pointer, ",") != NULL){
//Then I don't know how to fill the struct vector.
}
return 0;
}
I just pasted my old code to show you that I'm actually trying to do something.
I couldn't find a way to do what I need with this code, so I can get total differente code ideas to reach my goal.
In the old code, I need to restart the loop to change to the next value of the currently lane, then I can't add something like this:
while( (token = strtok(pointer, ",") ) != NULL ){
acc[0].num_acc = token;
// Now I need to set pointer as NULL and read the token again, to get the next value of the first row. But I can't do it like this. ;\
}
Since the data in the file are uniform, you can use sscanf. Keep track of an index that indicates which account from the array to fill.
sscanf(buffer, "%d,%24[^,],%lf",
&(acc[index].num_acc),
acc[index].name,
&(acc[index].value));
I have an array of pointers (char**) which contain some strings. The array ends with an empty string ('\0'). I am supposed to search for a specific word in that array of strings and delete the whole line (ofc using realloc and shortening the array of strings). I'm having hard time doing this, I keep getting 'bad ptr' error.
My code:
void deleteSentence(char **text){
char *word,*fptr;
int i=0;
word=(char*)calloc(BUFFER,sizeof(char));
printf("Enter word to delete sentences:\n");
gets(word);
while(text[i][0]!='\0'){
char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
strcpy(str,text[i]);
fptr=strtok(str,DELIM);
while(fptr!=NULL){
if(strcmp(fptr,word)==0){
int j=i;
while(text[j][0]!='\0'){
text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
strcpy(text[j],text[j+1]);
j++;
}
free(text[j]);
}
fptr=strtok(NULL,DELIM);
if(fptr!=NULL)
i++;
}
}
}
Help much appreciated :)
You're leaking memory like a sieve leaks water, and overrunning your arrays in at least two places. Furthermore the integration of input with the functional purpose of this code does literally nothing to help. The function should do one thing and one thing only:
Given a pointer to an array of char* pointers terminated with an empty string (or NULL), delete all strings in the pointer array that contain word. The resulting potentially compacted array is the return value of the function.
Consider this:
char ** deleteSentances(char **text, const char *word)
{
char **dst = text, **src = text, **res = text;
size_t size = 1, deleted = 0;
// loop while we have a non-null string that isn't empty
while (*src && (*src)[0])
{
char *tmp = strdup(*src);
if (tmp == NULL)
{
perror("Failed to allocate tmp");
exit(EXIT_FAILURE);
}
char *token = strtok(tmp, DELIM);
// search for matching word
while (token && strcmp(word, token))
token = strtok(NULL, DELIM);
// if not found, keep the string. otherwise delete it.
if (!token)
{
*dst++ = *src++;
size++;
}
else
{
free(*src++);
++deleted;
}
// don't need this.
free(tmp);
}
// resize the original array (which could have only gotten smaller)
if (deleted > 0)
{
res = realloc(text, size * sizeof(*res));
if (res == NULL)
{
perror("Failed to allocate res");
exit(EXIT_FAILURE);
}
res[size-1] = *src;
}
return res;
}
Hopefully that explains enough. The code is called like this:
char **text, *word;
//... populate text with strings
//... populate word with prospect word
text = deleteSentances(text, word);
Memory Leaks O'Festival
The OP wanted to understand where memory leaks were in the original posted algorithm. Consider the following first and foremost: For every allocation, there should be a known point of free'ing that memory. This example is somewhat difficult to nail that concept down simply because you're bringing dynamic allocations to the function, and some of them are going to be kept.
That said, consider the following places of interest. We assume coming in to this that at some point we allocated a pointer-array of this form:
char **text = malloc(N * sizeof(*text));
I.e. we have N character points. In each of those, we further assume a dynamic allocation for a character string has also transpired:
for (int i=0; i<(N-1); ++i)
{
//... compute length of next string
text[i] = malloc(length * sizeof(**text));
//... copy in next string to text[i]
}
And finally, the last character pointer in the text array is either NULL or points to a dynamic string of length 0 (i.e. a 0-length terminated string).
Whew. Ok. after all of that lets look at your algorithm:
void deleteSentence(char **text)
{
char *word,*fptr;
int i=0;
// Leak 1: allocate a single buffer of BUFFER-length.
// this is never freed anywhere in this function
word=(char*)calloc(BUFFER,sizeof(char));
printf("Enter word to delete sentences:\n");
// Problem: gets() is so evil and bad it has been deprecated from
// the C langage and will not be available in the next release.
// use fgets() instead.
gets(word);
while(text[i][0]!='\0')
{
// Leak 2: Done N times, where N is the number of strings in
// your original array. again, this is never freed.
char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
strcpy(str,text[i]);
fptr=strtok(str,DELIM);
while(fptr!=NULL)
{
if(strcmp(fptr,word)==0)
{
int j=i;
while(text[j][0]!='\0')
{
// Leak 3: Done M-N times for ever string we find in position
// M of the original array. This can be *huge* if there are
// a decent number of number of reductions that crunch your
// original array down.
text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
strcpy(text[j],text[j+1]);
j++;
}
// Problem: this just freed the termination string, which should
// never be done. We now have undefined behavior for the rest
// of this algorithm since the terminatingg string is invalid.
free(text[j]);
// Problem: You shoud break right here. See below for why
}
// Problem: you're missing an else condition here. At this point
// if the strcmp() found a match there is no reason to continue
// the loop. You found a match and deleted the string, crunching
// all the other string down one slot in a most-inefficient
// memory-leaking algorihm.
fptr=strtok(NULL,DELIM);
// Problem: the logic here is completely wrong. The i in this case
// should be incremented OUTSIDE the inner while loop. Furthermore
// the test is backwards.
if(fptr!=NULL)
i++;
}
}
}
In short, if it were possible to leak more memory than you did in that algorithm, I'm hard pressed to see how. The posted code I provided will work given the confines of the description I presented, and should be carefully looked to, even stepped through with a debugger line-y-line, to better understand how it works.