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.
Related
I'm trying to figure out why this doesn't work.
I'd like to take data from a file using the 'getline()' function and convert the string so that the slashes ('/') that are not in quotes are replaced with new line characters. I'd like to avoid copying the string to another if possible.
I tried my program below, with two attempts to process the same data. The first attempt wasn't quite right. I expected to see the following in both cases:
ABC
DEF'/'GH
But
printf("%s",newline);
only returns this:
ABC
DEF'/'
and:
printf("%s",newline2);
returns a segmentation fault.
Because the getline() function returns the string as a char array with memory pre-allocated to it, I feel a ridiculous solution would be:
char lines[5000000];
strcpy(lines,datafromgetline);
char* newline=parsemulti(lines,10); //prints data almost correctly
printf("%s",newline);
But could I somehow do this where I don't have to allocate local stack space or memory? Can I somehow modify the incoming data directly without a segmentation fault?
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
// replaces all occurrences of / not within single quotes with a new line character
char* parsemulti(char* input,int inputlen){
char* fms=strchr(input,'/');
char output[100000]; //allocate tons of space
if (!fms){
return input;
}else{
int exempt=0,sz=inputlen;
char aline[5000];
char*inputptr=input,*lineptr=aline;
memset(aline,0,5000);
while(--sz >= 0){
if (*inputptr=='\''){exempt=1-exempt;} //toggle exempt when ' is found
if (*inputptr=='/' && exempt==0){
*lineptr='\0';
strcat(output,aline);
lineptr=aline;
strcat(output,"\r\n");
}else{
*lineptr=*inputptr;lineptr++;
}
inputptr++;
}
if (exempt==1){printf("\nWARNING: Unclosed quotes\n");}
*lineptr='\0';
strcat(output,aline);
strcat(output,"\r\n");
}
strcpy(input,output);
return input;
}
int main(){
char lines[5000];
strcpy(lines,"ABC/DEF'/'GH");
char* newline=parsemulti(lines,10); //prints data almost correctly
printf("%s",newline);
char* lines2="ABC/DEF'/'GH";
char* newline2=parsemulti(lines2,10); //returns segmentation fault
printf("%s",newline2);
return 0;
}
Two lines
char lines[5000];
strcpy(lines, "ABC/DEF'/'GH");
will
allocate memory for 5000 objects of type char on stack
copy string literal contents to memory pointed by name "lines", which you can modify
on the other hand
char *lines2 = "ABC/DEF'/'GH";
defines pointer to string literal that is usually located in read only memory.
Read only, as in do not modify me :)
You tagged this C so I assume You are talking about using getline() function - not a part of C standard, but provided by GNU C Library, that manages memory on it's own (so basically it can, and will do memory allocations, unless you preallocate it. It uses only heap memory, so if preallocated size is too small it reallocates it. Thus You can't provide address to stack char array instead).
To actually find and replace escape character from string, I'd say you should not reinvent wheel and use library string functions.
char *line = NULL;
char *needle;
ssize_t line_size;
size_t size = 0;
line_size = getline(&line, &size, stdin);
while (line_size != -1) {
needle = strchr(line, '/');
while (needle) {
if (needle != line && !(*(needle - 1) == '\'' && *(needle + 1) == '\''))
*needle = '\n';
needle = strchr(needle + 1, '/');
}
printf("%s", line);
line_size = getline(&line, &size, stdin);
}
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 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.
I am going through The C Programming Language by K&R and trying to understand character pointers and arrays.
I am creating a function in C that reads multiple lines from stdin and stores the lines (char*) in an array of character pointers (char* []).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum {MAXINPUT = 1024, MAXLINES = 100};
/* Reads at most `maxLines` lines and stores them in an array of char pointers. Returns number of lines read. */
int readlines(char* lineptr[], int maxLines);
/* Takes a single line input from stdin and stores it in str. Returns str length. */
int getInputLine(char* str, int maxInput);
int main(int argc, char** argv) { ... }
int readlines(char* lineptr[], int maxLines) {
/* Return number of lines read. */
int numLines = 0;
/* Buffer to store current line being read. */
char currentLine[MAXINPUT];
/* Terminate loop when enter is pressed at empty input or number of lines exceeds max. */
while(getInputLine(currentLine,MAXINPUT) && numLines < maxLines) {
/* Address of current line's first character is set to the appropriate index at lineptr. */
lineptr[numLines] = currentLine;
/* Both currentLine and lineptr[numLines] print accurately (note they are the same). */
printf("CURRENT LINE:\t %s\n",currentLine);
printf("lineptr[%d]:\t %s\n",numLines,lineptr[numLines]);
numLines++;
}
/* ISSUE: Outside the loop, lineptr does NOT print anything. */
printf("\nLOOPING\n");
for(int i = 0; i < numLines; i++) {
printf("%d: %s\n",i,lineptr[i]);
}
/* ISSUE: currentLine (which should be the last line entered) ALSO does not print outside the while. */
printf("\ncurrentLine: %s",currentLine);
return numLines;
}
My issue is that in the while(), the contents of lineptr and currentLine print accurately. But outside the while(), both lineptr and currentLine do not print anything.
And of course, this issue persists when I try to read lines into a char* [] in the main() and try to print its contents.
Why is it that the contents at the addresses being accessed by lineptr are printing inside the loop but not outside? Am I missing something obvious?
That's because you have a single buffer called currentLine into which you read text. Then you assign the address of currentLine to your lineptr[i], and proceed to overwrite its contents with new text. So, all your lineptrs essentially point to the same one location, which is the address of currentLine, and currentLine contains only the last line that you read. I suppose the loop does not print anything because the last line you read is empty.
So, to get this to work, you need to read a line into currentLine, measure its length, use malloc() to allocate enough memory for that line, copy the line from currentLine to the allocated memory, and store the pointer to the allocated memory in lineptr[i].
This line
lineptr[numLines] = currentLine;
just assigns a pointer to lineptr[numLines]. There are couple of issues with that:
Every line points to the same pointer.
The pointer is invalid after you return from the function.
You need to use something akin to:
lineptr[numLines] = strdup(currentLine);
Remember that strdup is not a standard C library function. If your platform does not support it, you can implement it very easily.
char* strdup(char const* in)
{
char* ret = malloc(strlen(in)+1);
return strcpy(ret, in);
}
VARIABLES AREN'T SET IN STONE YET! Excuse if if no indention. I am new to this site. Anyway, I have a text document of a list of games in five different categories, and I need to some help with memory allocation VIA typedef. How would one do it? So far, this is what I have:
/*
Example of text document
2012 DotA PC 0.00 10
2011 Gran Turismo 5 PS3 60.00 12
list continues in similar fashion...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//function prototype here
char **readFile(char *file);
char *allocateString(char temp[]);
typedef struct
{
int year;
char name[100];
char system[10];
float price;
int players;
}game;
int main(void)
{
char **list;
system("pause");
return 0;
}
//function defined here
char **readFile(char *file) //reads file and and allocates
{
FILE* fpIn;
int i, total=0;
fpIn = fopen("list.txt", "r");
if (!fpIn)
{
printf("File does not exist");
exit(101);
}
/*
allocate memory by row here VIA for loop with the total++ to keep track of the
number of games
*/
/*
allocate memory individually for each item VIA "allocateString by using going
to set list[i] = allocateStrng(tmpList) using for loop the for loop will have
for (i=0; i<total; i++)
*/
return;
}
//allocateString here
char *allocateString(char temp[]);
{
char *s;
s = (char*)calloc(strlen(temp+1), sizeof(char)));
strcpy(s, temp);
return s;
}
Usually you'd allocate a decent amount of memory up front, detect situations where that amount is not enough, and enlarge the allocation in those cases using realloc (or malloc followed by memcpy and free). This advice holds for both the buffer into which you read the current line (to be passed as temp to allocateString) and the array to hold the sequence of all lines.
You can detect an insufficient buffer size for the line buffer when after calling fgets(buf, bufsize, fpIn) the strlen(buf) == bufsize - 1 but still buf[bufsize - 2] != '\n'. In other words, when reading filled the whole buffer, but still didn't reach a newline. In that case, the next read will continue the current line. You might want an inner loop to extend the buffer and read again for as long as it takes.
Note that your allocateString pretty much duplicates strdup, so you might want to use that instead.
The links in the above text mainly come from the manual of the GNU C library. cppreference.com is another good source of C function documentation. As are the Linux man pages.
s = (char*)calloc(strlen(temp+1), sizeof(char)));
//the name of the array is a pointer, so you are doing pointer arithmetic.
//I think you want strlen(*temp+1, sizeof(char)));
// or strlen(temmp[1]) it isn't clear if this is a pointer to a string or an array
// of strings
//you need the length of the string *temp is the content which temp points to
//strcpy(s, temp);