I am trying to read a file line by line, and get each line as a charĀ * to a dynamic string, the code I am using used to work and without changing it (or noticing it), it has ceased to work, accsesing the reed information results in an error. Here is a MRE of my code for getting one line:
#include <stdio.h>
#include <string.h>
#define MAX_STR_SIZE 10000
int main(void)
{
char* filePath; // is set by other working part of program to a real readable file address.
while (fgetc(filePath) != EOF) // an extra chracter is in the data files to account for this cheack.
{
char tempStr[MAX_STR_SIZE] = { 0 };
char* str = NULL;
fgets(tempStr, MAX_STR_SIZE, filePath);
tempStr[strcspn(tempStr, "\n")] = 0;
str = malloc(sizeof(char) * (strlen(tempStr) + 1)); // does not work
strcpy(str, tempStr);
}
}
The error:
Exception thrown at 0x00007ff95448d215 in GifProject.exe: Access violation writing location 0xFFFFFFFFEA1854F0.
It is difficult to diagnose your problem without a complete compilable program that exhibits the problem, but from the code fragment and the debugging information in the image, it seems you do not include <stdlib.h> and the prototype inferred by the compiler for malloc() from the actual argument is int malloc(size_t), leading to undefined behavior when you store the return value into the pointer str: because of the missing prototype, the compiler generates code that converts the return value from int to char *, sign extending from 32-bit to 64-bits, producing a meaningless pointer.
Note that you should also test the return value of fgets to properly handle end of file, and you should test for potential malloc failure before calling strcpy or better: use strdup that allocates and copies a string in a single call.
Here is a modified version:
#include <stdlib.h>
#include <string.h>
#define MAX_STR_SIZE 4096
char *readline(FILE *file) {
char tempStr[MAX_STR_SIZE];
if (!fgets(tempStr, sizeof tempStr, file)) {
/* end of file: return a null pointer */
return NULL;
}
/* strip the trailing newline if any */
tempStr[strcspn(tempStr, "\n")] = '\0';
/* allocate a copy of the string and return it */
return strdup(tempStr);
}
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 am trying to concatenate two strings in C and receive a "Thread 1: signal SIGABRT" error.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
int main() {
char name[50];
ifile = fopen("stats.list", "r");
for(;;) {
fscanf(ifile, "%s%f%f", name, &sky, &stddev);
if (feof(ifile))
break;
char ext[5] = ".par";
dataparsFile = strcat(name, ext);
dataparsFile = fopen(dataparsFile, "w");
fprintf(dataparsFile, "%s\n",
"stuff gets read in to file named after new string";
fprintf(ofile, "phot ");
fprintf(ofile, "%s%s%s%s%s%s \n",
", datapars=", dataparsFile);
}
fclose(ifile);
fclose(ofile);
The goal of the code is to take an image name that is read in and add on the .par extension. Then, I want to open a file with that name of image+.par and write into it. Since I will have a couple hundred such files, I need to loop through them with the name changing each time.
The problem is name is not initialized. You see, in c strings use a convention, they are any sequence of ASCII (probably some other printable characters, but in principle just ASCII) that must be followed by a '\0' byte that marks the end of the string.
Your name array doesn't have this '\0' so strcat() tries to find it but it fails and perhaps it reads beyond the end of the array, although anyway reading uninitialized data is undefined behavior.
The way strcat(dst, src) works is pretty much like this
char *
strcat(char *const dst, char *src)
{
// Make a pointer to keep dst's address
// unchanged and return it
char *ptr = dst;
// Compute search for the end of the destination
// string to start copying there
while (*ptr != '\0')
ptr++;
// Copy all the characters from `src' until the '\0'
// occurs
while (*src != '\0')
*(ptr++) = *(src++);
*ptr = '\0';
return dst;
}
As you see, this is very inefficient if you call strcat() many times, and it will certainly not work if you pass either of the parameters before initializing it.
In fact, it's terribly unsafe because there is no bound checking, the caller has to make sure that the destination array is large enough to hold both strings.
I would like to create a function to read file line by line. One every line is one name.
int readConfig(char ** path, FILES ** files )
{
FILE* f;
f = fopen("file", "r");
int ch;
while ((ch=fgetc(f)) != EOF )
{
}
return 0;
}
How to use the fgetc function to parse the file? And how to get the results to the files[count].name?
Right off the bat:
char configFile [11] = "kernels.cfg";
[11] is too small. Try:
char configFile [12] = "kernels.cfg";
or
char configFile [] = "kernels.cfg"; /* let the compiler do the counting */
Also char is too small for ch -- use:
int ch;
You may also find fgets() -- which reads a whole line at at time -- simpler to use than fgetc().
You are getting SIGSEGV because of modifying string literal and that causes an undefined behavior (e.g. your SIGSEGV). I am not sure what should be stored in filename and name variables. If by line:
strcpy(files[count].filename,'.bin');
you've meant to add a '.bin' to filename variable, then this approach is wrong. You should use strcat. strcpy would write to filename from beginning of this variable, so some chars previously saved there would be overwritten. strcpy also adds a null termination char, so if you wanted to print it out, printf would stop on that \0 char and won't go further. However, the real problem is that you should allocate with malloc some space for your variables in struct. Then you will be able to modify them.
Consider simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct file {
char* name;
char* filename;
};
int main(void)
{
struct file x;
x.name = malloc(30);
x.filename = malloc(40);
strncpy(x.name, "copied_string", 13);
printf("%s\n", x.name);
strcat(x.name, "_suffix");
printf("%s\n", x.name);
strcpy(x.name, "erased");
printf("%s\n", x.name);
free(x.name);
free(x.filename);
return 0;
}
output:
copied_string
copied_string_suffix
erased
This should make it a little more clear what's the origin of your crash. You should also consider using fgets or getline. Remember to free what you've malloc'd.
EDIT:
Calling readConfig(&path, &files); results in passing to readConfig a pointer of type FILES (*)[256]. Consider changing FILES files[256]; to
FILES* files = malloc(sizeof(FILES)*256);
and later call your function like readConfig(&path, files);
Then you would pass to readConfig function a compatible type of files.
I am new to C, and trying to implement whoami, as an exercise to myself. I have following code:
#define _POSIX_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h> // strtok
int str_to_int(const char *str)
{
int acc = 0;
int i;
for (i = 0; str[i] != '\0'; ++i) {
acc = (10 * acc) + (str[i] - 48); // 48 -> 0 in ascii
}
return acc;
}
int main()
{
FILE *passwd;
char *line = NULL;
size_t line_size;
passwd = fopen("/etc/passwd","r");
uid_t uid = getuid();
while (getline(&line, &line_size,passwd) != -1) {
char *name = strtok(line,":");
strtok(line,":"); // passwd
char *user_id = strtok(line,":");
if (str_to_int(user_id) == uid) {
printf("%s\n",name);
break;
}
}
fclose(passwd);
return 0;
}
Do I need to save line pointer inside of the while loop. Because I think strtok modifies it somehow, but I am not sure if I need to copy the line, or starting address of the line before I use it with strtok.
strtok is a horrid function. I don't know what documentation you read (if any?) but it both modifies the buffer it is passed and retains an internal pointer into the buffer; you should only pass the buffer the first time you use it on a given line, and pass NULL subsequently so it knows to pick up where it left off instead of starting at the beginning again (which won't actually work quite right because it stomped on the buffer...).
Better, find some other way to parse and stay far away from strtok.
It might be safer to use strtok_r. It is safer in a multi-threaded situation. That may not apply in this case, but it is sometimes better just to assume that some point any snippet you write might end up in a multi-threaded app. The following is the OP code modified to use strtok_r.
char *pos;
char *name = strtok_r(line,":",&pos);
strtok_r(NULL,":",&pos); // passwd
char *user_id = strtok_r(NULL,":",&pos);
And, yes, strtok (and strtok_r) do modify the given input buffer (first parameter). But it can be safe if used properly. Since strtok returns a pointer to a buffer inside the given string, you need to be careful how you use it. In your case, when it breaks out of the loop, name and user_id will point to a value inside the line buffer.
And you maybe should read the man pages for getline. The way you are using it, it returns an allocated buffer that your application is responsible for freeing. That might be what you are aiming for, but I mention it because I don't see a free call for it in the posted code.
I totally agree with geekosaur (and Mark). Paraphrasing his comment, you can modify the above code as following:
while (getline(&line, &line_size, passwd) != -1) {
char *name = strtok(line,":");
strtok(NULL,":"); // passwd
char *user_id = strtok(NULL,":");
if (str_to_int(user_id) == uid) {
printf("%s\n",name);
break;
}
}
You should pass NULL for the strtok invocations other than the first one.