I need to read some data from text file and store it in 2D-array.
This code works good:
#include <string.h>
#include <stdio.h>
int main() {
FILE *f = fopen("Read.txt", "r");
char buff[100][100];
char str[100];
int i = 0;
while(fgets(str, 100, f)) {
strcpy(buff[i], str);
i++;
}
return 0;
}
But why doesn't it work when I try to change buff definition in line 5 to:
char (*buff)[100];
I expected this definition to work too.
The error I get:
Run-Time Check Failure #3 - The variable 'buff' is being used without being defined
char (*buff)[100];
Here buff is a pointer to an array of 100 characters. So first you should make the pointer point to valid memory location before storing some value in it.
Presuming you want to go for dynamic memory allocation then you can have
char *buff[100];
Now in the fgets() loop allocate memory to each pointer individually like
buff[i] = malloc(100);
Note here buff is an array of 100 char pointers.
Related
In the below code, I am trying to read an input line from STDIN using function usergetline and in the main function, I am assigning the input string to an array of char pointers. (char *lineptr[MAXCOUNTLINE])
While within the 1st while loop, the input line is stored in the lineptr (as can be seen when I print the lineptr[iplinecount]), however, once I come outside the loop, all it prints is new line.
#include <stdio.h>
#include <string.h>
/* function declarations */
int usergetline(char *, int);
/* constants */
#define MAXCOUNTLINE 10
#define MAXLINECOUNTWIDTH 100
#define DEFPRINTFRLASTCOUNT 8
void main(int argc, char *argv[])
{
char *ipline;
int iplinecount,shifter;
iplinecount=0;
char *lineptr[MAXCOUNTLINE];
/* continue to accept the lines till the time EOF is not encountered and
* max count of lines is not exceeded */
while((iplinecount < MAXCOUNTLINE) && (usergetline(ipline,MAXLINECOUNTWIDTH) >0)){
lineptr[iplinecount] = ipline;
#ifdef DEBUG
printf("iplinecount: %d\n",iplinecount);
printf("ipline: %s\n",ipline);
printf("strlen of ipline: %d\n",strlen(ipline));
printf("*(lineptr+iplinecount): %s\n",lineptr[iplinecount]);
printf("strlen of *(lineptr+iplinecount): %d\n",strlen(lineptr[iplinecount]));
printf("value at ipline %p\n",ipline);
printf("value at *(lineptr+iplinecount) %p\n",lineptr[iplinecount]);
#endif
iplinecount++;
}
printf("iplinecount = %d\n",iplinecount);
shifter=0;
while(shifter < iplinecount){
printf("strlen: %d\n",strlen(*(lineptr+shifter)));
printf("%s\n",*(lineptr+shifter));
shifter++;
}
}
/* usergetline: function to accpet an input line from STDIN */
int usergetline(char *ipline, int maxlengthofip)
{
char c;
int i=0;
while((maxlengthofip-1) && ((c=getchar()) != EOF) && (c != '\n')){
maxlengthofip--;
*ipline=c;
ipline++;
i++;
}
if (c=='\n'){
*ipline='\n';
ipline++;
i++;
}
*ipline = '\0';
return i;
}
Suppose this file name is exercise5-13.c.
I am using cygwin environment. After compilation (with -D DEBUG flag), when I execute the program, as in. ./exercise5-13.exe
Output is:
testing
iplinecount: 0
ipline: testing
strlen of ipline: 8
lineptr[iplinecount]: testing
strlen of lineptr[iplinecount]: 8
value at ipline 0xffffcdf0
value at lineptr[iplinecount] 0xffffcdf0
iplinecount = 1
strlen=0
My limited understanding and argument against initialization of array of char pointer is that when I am assigning (line 21)
'''
lineptr[iplinecount] = ipline;
'''
then, lineptr is being assigned an address of ipline which in itself is pointing to the string constant fetched from the STDIN testing in this case.
I was expecting that eachnew string fetched from STDIN would be first stored in line pointer and from their, the address of the first element of the string would be stored in the char pointer array. However, char pointer array is empty?
You are using the uninitialized pointer
char *ipline;
//...
usergetline(ipline,MAXLINECOUNTWIDTH)
within the function usergetline that invokes undefined behavior.
You need to allocate dynamically memory where you are going to read data and the address of the allocated memory to assign to the pointer ipline. So the pointer ipline must be passed to the function by reference that is through a pointer to the pointer.
The function declaration in this case will look for example like
int usergetline(char **ipline, int maxlengthofip);
I'm writing a simple c program that reads lines from a text file into a char **. In my main function, I create the char * array, allocate memory for it, and pass a pointer to the array to another function to populate each index in the array with a char * representing the content of each line in the text file.
For some reason related to my memory management I'm guessing, I'm receiving a segmentation fault on the third iteration of my while loop, which copies the string into the array of strings. Why is this?
My code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getRestaurants(char ***restaurantsArray) {
FILE *restaurantsFile = fopen("./restaurants.txt", "r");
char *restaurant = (char *)malloc(50 * sizeof(char));
char *restaurantCopy = restaurant;
//fopen will return null if it is unable to read the file
if (restaurantsFile == NULL) {
free(restaurant);
return;
}
int index = 0;
while (fgets(restaurantCopy, 50, restaurantsFile)) {
// segfault occurs the third time the following line is executed
*restaurantsArray[index] = (char*)malloc(50 * sizeof(char));
strcpy(*restaurantsArray[index], restaurantCopy);
printf("%s", restaurantCopy);
printf("%s", *restaurantsArray[index]);
index++;
}
fclose(restaurantsFile);
free(restaurant);
}
void main() {
char **restaurantsArray = (char **)malloc(100 * sizeof(char *));
char **restaurantsArrayCopy = restaurantsArray;
getRestaurants(&restaurantsArrayCopy);
}
Expected Result:
firstline
firstline
secondline
secondline
thirdline
thirdline
and so on, if the provided restaurants.txt file contains:
firstline
secondline
thirdline
In getRestaurants, restaurantsArray is declared as char ***Array. In the line *restaurantsArray[index] = …;, it takes restaurantsArray[index] and attempts to use it as a pointer (by applying the * operator). But restaurantsArray is merely a pointer to the restaurantsArrayCopy in main. restaurantsArrayCopy is merely a single object, not an array. It is just one char **. In getRestaurants, using restaurantsArray[index] with anything but zero for index uses some undefined thing.
There is no need to pass &restaurantsArrayCopy from main to getRestaurants. Just pass restaurantsArray. This is a pointer to allocated space.
Then, in getRestaurants, instead of *restaurantsArray[index] = …;, use restaurantsArray[index] = …;, without the *. This will assign a value to an element in restaurantsArray, which is what you want to do. Similarly, remove the * in the strcpy and the printf.
I am doing a project of creating a bot that surfs the internet.
I have to code it in C and for now I'm focusing on the choice of the address where it will go (choosen from a list in a file). This works properly but when I display the addresses the bot has chosen, some are truncated to 24 characters and end with "!" which makes the code unusable with long addresses. Does anyone have any idea of where it might come?
The program :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
int main() {
FILE* file = fopen("test.txt", "r+");
char *line = NULL;
char *tab[1023];
int tailleTab = 0;
line = malloc(sizeof(*line));
if(line == NULL)
return(EXIT_FAILURE);
while((fgets(line, 1023, file)) != NULL ) {
if(line[0] != '#' && line[0] != '\n') {
tab[tailleTab] = line;
line = malloc(sizeof(*line));
tailleTab++;
}
}
srand(time(NULL));
int n = rand()%tailleTab;
printf("\n%d = %.32s\n", n, tab[n]);
printf("%s\n", tab[n]);
fclose(file);
}
The file from which the address is chosen:
www.google.com
www.wikipedia.org
www.dahunicorn.xyz
www.cloudimperiumgames.com
www.robertspaceindustries.com
www.candybox2.net
www.42.com
www.1337.com
The main problem is this:
line = malloc(sizeof(*line));
This only allocates a single character to line. The expression *line is a char which means you allocate sizeof(char) bytes, and sizeof(char) is defined to always be 1.
That means your call to fgets will write out of bounds of your allocated memory and you will have undefined behavior.
There's no reason to actually allocate line dynamically. Instead create it as an array, and then use strdup when saving it in the tab array. Either that or allocate more memory (1023 is a good number, since that's amount you pass to fgets).
As already explained in another answer, with this code:
line = malloc(sizeof(*line));
you are allocating with malloc a single char on the heap, since the expression *line is equivalent to a char (as line is declared as char *).
I would simplify your code using named constants instead of magic numbers like 1023 that are spread through code (and make it harder to maintain), in addition to just reserving space for the temporary line buffer on the stack instead of dynamically allocating it on the heap, e.g.:
/* Instead of: line = malloc(sizeof(*line)); */
#define LINE_MAX_SIZE 1024
char line[LINE_MAX_SIZE];
Also consider doing:
#define TAB_MAX_ITEMS /* 1023 or whatever */
char* tab[TAB_MAX_ITEMS];
In the while loop consider using LINE_MAX_SIZE instead of the magic number 1023:
while ((fgets(line, LINE_MAX_SIZE, file)) != NULL ) {
You may also want to add a check to the index in the tab array, to avoid buffer overruns:
if (tailleTab >= TAB_MAX_ITEMS) {
/* Index out of range */
...
}
/* tailleTab is a valid index.
* Deep-copy the line read in the temporary buffer
* and save a pointer to the copy into the tab array.
*/
tab[tailleTab] = strdup(line);
In production code you should also loop through the pointers stored in the tab array, and call free on the them to release the memory allocated on the heap.
I have a function whichtakes a file, reads it line by line, puts every line in a *char[], puts this twodimensional array in a struct, and returns this struct:
wordlist.h:
#ifndef H_WORDLIST
#define H_WORDLIST
typedef struct {
char **chWordsList;
int listlen;
}Wordlist;
Wordlist getWordlistFromFile(char *chFilename);
char *getRandomWord();
#endif
The function (plus headers):
#include "wordlist.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define WORDSIZE 100
Wordlist getWordlistFromFile(char *chFilename){
FILE *file = fopen(chFilename,"r");
if (file == NULL){
printf("Unable to open file %s. Check if the file exists and can be read by this user.\n",chFilename);
exit(1);
}
char chWord[WORDSIZE];
int intFileSize = 0;
//First: coundt the amount of lines in the file
while((fgets(chWord,WORDSIZE,file) != NULL)){
++intFileSize;
}
rewind(file);
char *chWordList[intFileSize];
for (int count = 0; (fgets(chWord,WORDSIZE,file) != NULL); ++count){
chWordList[count] = malloc( strlen(chWord +1));
strcpy(chWordList[count],chWord);
chWordList[count][strlen(chWord) -1] = 0;
}
fclose(file);
Wordlist wordlist;
wordlist.chWordsList = chWordList;
wordlist.listlen = intFileSize;
for (int i = 0; i < wordlist.listlen; ++i){
printf("%s\n", wordlist.chWordsList[i]);
}
return wordlist;
}
So far this works great. The last for loop prints exactly every line of the given file, all fully expected behaviour, works perfect. Now, I actually want to use the function. So: in my main.c:
Wordlist list = getWordlistFromFile(strFilePath);
for (int i = 0; i < list.listlen; ++i){
printf("%s\n", list.chWordsList[i]);
}
This gives me the weirdest output:
abacus
wordlist
(null)
(null)
��Ⳏ
E����H�E
gasses
While the output should be:
abacus
amused
amours
arabic
cocain
cursor
gasses
It seems to me almost like some pointers get freed or something, while others stay intact. What is going on? Why is wordlist perfect before the return and broken after?
char *chWordList[intFileSize]
This array of strings is allocated on stack since it's declared as a local of getWordlistFromFile. Upon exiting the function the stack pointer is decreased and the array is no longer valid.
You should use the same approach used for the single string: allocate in on heap.
char **chWordList = malloc(intFileSize*sizeof(char*))
In this way the array will persist the scope of the function and you will be able to use it after the call to the function.
Because you are returning pointers to objects whose lifetime has expired. In particular, chWordsList inside the return value points to an object whose lifetime ends when the function returns. When you dereference that pointer you get undefined behavior (UB); therefore any result would not be surprising.
What you need to do is malloc memory for the chWordList instead of declaring it as a local array:
char **chWordList = malloc(intFileSize * sizeof(char*))
Change
char *chWordList[intFileSize];
to
char **chWordList = malloc(sizeof(char *) * intFileSize);
i.e allocated chwordList and set that in the WordList.
Your code is returning array variable chWordList allocated on stack, so it will not be valid once the function getWordlistFromFile() completes and returns to main().
This function is supposed to get a parameter as the pointer of a file and put all file into the struct anagram, then write it to another file. Right now the each data has a lot of space bewteen them. The charCompare is working fine since i make a test file to test it.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "anagrams.h"
#define SIZE 80
//struct
struct anagram {
char word[SIZE];
char sorted[SIZE];
};
void buildDB ( const char *const dbFilename ){
FILE *dict, *anagramsFile;
struct anagram a;
//check if dict and anagram.data are open
errno=0;
dict= fopen(dbFilename, "r");
if(errno!=0) {
perror(dbFilename);
exit(1);
}
errno=0;
anagramsFile = fopen(anagramDB,"wb");
char word[SIZE];
char *pos;
int i=0;
while(fgets(word, SIZE, dict) !=NULL){
//get ripe of the '\n'
pos=strchr(word, '\n');
*pos = '\0';
//lowercase word
int j=0;
while (word[j]){
tolower(word[j]);
j++;
}
/* sort array using qsort functions */
qsort(word,strlen(word), sizeof(char), charCompare);
strncpy(a.sorted,word,sizeof(word));
fwrite(&a,1,sizeof(struct word),anagramsFile);
i++;
}
fclose(dict);
fclose(anagramsFile);
}
data:
10th 1st 2nd
A probable cause is the size argument passed to qsort(). From the linked reference page for qsort():
size - size of each element in the array in bytes
Therefore the size argument should be 1, which is guaranteed to be sizeof(char), and not sizeof(char*) which is likely to be 4 or 8. The posted code incorrectly informs qsort() that word is pointing to an array of 4 (or 8) times larger than the actual array and qsort() will access memory it is not supposed to. Change to:
qsort(word,strlen(word), 1, charCompare);
Another possible cause is buffer overrun caused by this line:
strncpy(&a.sorted[i],word,sizeof(word));
i is being incremented on every iteration of the while loop but sizeof(word) is always being written. The values of SIZE and BUFSIZ are not posted but even if they were equal the strncpy() will write beyond the bounds of a.sorted after the first iteration.
Other points:
fgets() is not guaranteed to read the new-line character so check return value of strchr() before dereferencing it.
tolower() returns the lowercase character, it does not change its argument.
why read into a temporary buffer (word) and copy? Just read directly into the struct members.