What is wrong with my program in C? - c

Code link
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OS_TYPE "/proc/sys/kernel/ostype"
#define OS_RELEASE "/proc/sys/kernel/osrelease"
#define V_BUFF 30
static const char * get_value(const char * file_path)
{
static char value[V_BUFF];
FILE *fd;
memset(value, 0, sizeof(value));
if ((fd = fopen(file_path, "r")) == NULL) {
fputs("Fopen function error.\n", stderr);
exit(EXIT_FAILURE);
}
while (fgets(value, V_BUFF, fd) == NULL) {
fputs( "Fscanf function error.\n", stderr);
exit(EXIT_FAILURE);
}
fclose(fd);
return value;
}
int main(void) {
fprintf(stdout, "%s%s", get_value(OS_TYPE), get_value(OS_RELEASE));
return EXIT_SUCCESS;
}
Where's wrong?
Why the result r same?
If added a fflush in while or out of while, the result also same.
Plz help me, tell what reason.
Thanks!

The arguments are evaluated then passed to fprintf to format them.
Since there's only one memory area (static) for both results, the last function call "wins" and you get twice the same result (note that order of evaluation is implementation defined, so you could get twice the first result, or twice the second)
Quickfix: as BLUEPIXY suggested, you could call fprintf twice:
fprintf(stdout, "%s", get_value(OS_TYPE));
fprintf(stdout, "%s", get_value(OS_RELEASE));
To fix that properly you'd have to allocate memory using malloc (char *value = malloc(V_BUFF);), but in that case you'd have to store the pointer to be able to free it, or pass an extra argument to the function, as a buffer to use internally, like some standard functions do.
const char * get_value(const char * file_path, char *value)
{
...
return value;
}
now you can get your call in one line with separate buffers and no memory leaks:
char vbuf[V_BUFF],obuf[V_BUFF];
fprintf(stdout, "%s%s", get_value(OS_TYPE,vbuf), get_value(OS_RELEASE,obuf));

Related

fopen() fails but seems to not return NULL?

I have got the following code:
#include <stdio.h>
#include "config.h"
#include <errno.h>
char buffer[50];
long long bufSize = 50;
FILE* fptr;
char* readConfig(char* buffer, size_t bufSize) {
fptr = fopen("config.txt", "rt");
if (fptr == NULL) {
return "error opening config file: %s", strerror(errno);
} else {
if ((fgets(buffer, bufSize, fptr)) == NULL) {
fclose(fptr);
return "error reading config file: %s", strerror(errno);
}
else {
fclose(fptr);
return buffer;
}
}
}
For test purposes I deleted the config.txt file so that the fopen() function should return NULL.
What wonders me is that fopen("config.txt", "rt"); fails, but when debugging the code it just skips the "if (fptr == NULL) {...}" part and directly jumps out of the function.
When going on with the debugging process, I get the following error when trying to work with the return Value of readConfig() "0xC0000005: Access violation reading location 0xFFFFFFFFA4E0EB70"
Cannot compile your code as you shared a snippet (no main()) and didn't include config.h.
#include <string.h> for strerror().
Suggest caller passes in local variables instead of global variables.
Instead of hard-coding the size in both buffer[50] and bufSize = 50; use sizeof to determine the size of the array. The other good alternative is to define a constant.
The fopen() mode "t" isn't standard, so either leave it out or tag your program with windows or whatever.
As you return on error, eliminate the unnecessary else & indentation.
The expression return "error opening config file: %s", strerror(errno); doesn't work the way you expect, it will evaluate the first part in void context then return the 2nd part strerror(errno). I was not able to otherwise reproduce any ill effects.
fgets() return NULL on eof or error but not appear to set errno. You can use feof() and/or ferror() to tell which if needed.
After the call to fgets() you call fclose() prior to inspecting errno, so it have the status of the fclose() call instead.
It's a bad design to return either error message or the value you read from the file as you cannot tell them apart. Changed to return NULL on success.
#include <errno.h>
#include <stdio.h>
#include <string.h>
char *readConfig(char *buffer, size_t bufSize) {
FILE* fptr = fopen("config.txt", "r");
if(!fptr)
return strerror(errno);
if(!fgets(buffer, bufSize, fptr)) {
fclose(fptr);
return "fgets eof/error";
}
fclose(fptr);
return NULL;
}
int main(void) {
char b[50];
const char *error = readConfig(b, sizeof b);
if(error) {
printf("error: %s\n", error);
return 1;
}
printf("%s", b);
}
Consider having caller open the file and pass in the FILE *. It gives you the flexibility, for instance, to use stdin as the file handle.
I prefer using goto instead of the multiple returns when resource cleanup is required. It's a bit more verbose here but each error case is handled the same way. When you swap the arguments you can document how they are related with recent compilers:
char *readConfig(size_t bufSize, char buffer[bufSize]) {
char *r = NULL;
FILE* fptr = fopen("config.txt", "r");
if(!fptr) {
r = strerror(errno);
goto out;
}
if(!fgets(buffer, bufSize, fptr)) {
r = "fgets eof/error";
goto out;
}
out:
fptr && fclose(fptr);
return r;
}

Segmentation Fault: 11 in ANSI C (C89)

So I've got a project I'm working on in ANSI C (C89) for class. I've gotten stuck in the process. I'm getting a
segmentation fault: 11
issue, and no matter what I look up, I can't seem to solve the issue. can someone look at my code and point me in the right direction?
/* CS315 Lab 3: C data types */
#include <stdio.h>
#include <stdlib.h> /*added this to provide a declaration for malloc*/
#define TENMB 1048576 /*1024 kilobytes or 10 megabytes */
#define ONEB 1
FILE * fp = NULL;
End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
initialize(int argc, char ** argv)
{
/* Open the file given on the command line */
if( argc != 2 )
{
printf( "Usage: %s filename.mp3\n", argv[0] );
return(EXIT_FAILURE);
}
FILE * fp = fopen(argv[1], "rb");
if( fp == NULL )
{
printf( "Can't open file %s\n", argv[1] );
return(EXIT_FAILURE);
}
return 0; /*this might need to change */
}
readFile(FILE * fp)
{
/* How many bytes are there in the file? If you know the OS you're
on you can use a system API call to find out. Here we use ANSI
standard function calls. */
long size = 0;
fseek(fp, 0, SEEK_END ); /* go to 0 bytes from the end */
size = ftell(fp); /* how far from the beginning? */
rewind(fp); /* go back to the beginning */
if( size < ONEB || size > TENMB )
{
printf("File size is not within the allowed range\n");
End(fp); /* switched from goto END:*/
}
printf( "File size: %.2ld MB\n", size/TENMB ); /* change %d to %ld, added .2 to print to 2 decimal places (maybe use f instead) */
/* Allocate memory on the heap for a copy of the file */
unsigned char * data = (unsigned char *)malloc(size);
/* Read it into our block of memory */
size_t bytesRead = fread( data, sizeof(unsigned char), size, fp );
free(data); /* deallocation */
if( bytesRead != size )
{
printf( "Error reading file. Unexpected number of bytes read: %zu\n",bytesRead ); /* changed from %d to %zu */
End(fp); /* switched from goto END:*/
return 0;
}
return 0;
}
int main( int argc, char ** argv )
{
initialize(argc, argv);
readFile(fp);
/* We now have a pointer to the first byte of data in a copy of the file, have fun
unsigned char * data <--- this is the pointer */
}
Thanks for any help!
In your code you have declared fp twice, both globally and locally
FILE * fp = NULL;
End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
initialize(int argc, char ** argv)
{
...
FILE * fp = fopen(argv[1], "rb");
...
Even though you are writing C89 there is no need to pick up the bad things with the standard. E.g. declare functions properly with a return type.
You say that this should be C89 code, but there are some aspects of this code that are not C89 compliant. I have included a modified version of your code below that fixes these things, compiles without warnings, and seems to run correctly. By way of a disclaimer, I never write in C89, so someone else may take issue with something here.
The segfault that you report is due to the double-declaration of fp, as pointed out by #BLUEPIXY in the comments to your question. You declare this file pointer first at file scope (i.e., fp is a "global" variable), and then at block scope within the function initialize(). The second declaration hides the first one within the block, so you open a file in initialize() and assign the resulting pointer to the block scope fp (which has automatic storage duration). When main() then calls readFile(), it is the file scope fp that is passed, and this fp is initialized to NULL. So fseek(fp, 0, SEEK_END) is called on a NULL pointer, and this causes the segfault. Changing the second declaration to an assignment fixes this problem:
fp = fopen(argv[1], "rb");
You can't mix variable declarations and code in C89, so you need to move the declarations to the beginning of the functions. Also, C89 does not support the %zu format specifier for size_t variables. Instead, use %lu and cast the size_t value bytesRead to (unsigned long).
I added a definition: ONEMB 1048576, and removed the TENMB definition. In the calculation of the file size, you were dividing the number of bytes by 10MB instead of 1MB, and I take it that you were in fact trying to calculate the number of MB.
I added a check for errors to the call to ftell(). Since ftell() returns a long, I added a size_t fileSize variable and cast the value of size to size_t before assigning it to fileSize. I changed theprintf() statement to:
printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB );
so that the file size is reported with more precision; this way, files smaller than 1 MB will not be reported as having a size of 0 MB.
I removed the cast from the call to malloc(), as it is absolutely not needed in C.
The assignment to bytesRead calls fread(), which takes a size_t parameter for the third argument, not a long. You originally had the long value size here, and this is one reason for the new fileSize variable. The following line had a comparison between bytesRead, which is size_t, and size. This should generate compiler warnings (you do have them on, don't you?) as using signed and unsigned types in the same expression can lead to difficulties, and so here I used the fileSize variable again.
You were missing the return statement at the end of main(), and your function definitions were missing their return type specifiers, so I also added these. I also noticed that your program was segfaulting when invoked with no arguments. This is because on errors in your initialize() function, you were returning to the calling function, which then called readFile() with a NULL pointer. You should instead exit() from the program. I have made these changes to all file error traps in the modified code.
There are some other issues with your code. I would prefer not to use the End() function. It does not test for errors during closing files, and will segfault if you pass in a NULL pointer. Also, the "Unexpected number of bytes read" error in readFile() will end up exiting successfully, since End() always exits with EXIT_SUCCESS.
I don't love the casting from long to size_t that I did, and someone else may have a better approach. What I was trying to manage here was that ftell() returns a long, which you use to calculate the file size, and fread() both takes and returns size_t values.
Most of what I did was in the readFile() function, and I removed your comments from this function to make it easier to see what was changed.
I compiled with:
gcc -std=c89 -Wall -Wextra -pedantic
#include <stdio.h>
#include <stdlib.h> /*added this to provide a declaration for malloc*/
#define ONEMB 1048576
#define ONEB 1
FILE * fp = NULL;
void End(FILE * fp)/*made END a function */
{
fclose(fp); /* close and free the file */
exit(EXIT_SUCCESS); /* or return 0; */
}
int initialize(int argc, char ** argv)
{
/* Open the file given on the command line */
if( argc != 2 )
{
printf( "Usage: %s filename.mp3\n", argv[0] );
exit(EXIT_FAILURE);
}
fp = fopen(argv[1], "rb");
if( fp == NULL )
{
printf( "Can't open file %s\n", argv[1] );
exit(EXIT_FAILURE);
}
return 0; /*this might need to change */
}
int readFile(FILE * fp)
{
long size = 0;
unsigned char *data;
size_t fileSize, bytesRead;
fseek(fp, 0, SEEK_END );
if ((size = ftell(fp)) == -1) {
fprintf(stderr, "ftell() error\n");
exit(EXIT_FAILURE);
};
rewind(fp);
if( size < ONEB || size > 10 * ONEMB )
{
printf("File size is not within the allowed range\n");
End(fp);
}
fileSize = (size_t) size;
printf( "File size: %.2f MB\n", (fileSize * 1.0)/ONEMB );
data = malloc(fileSize);
bytesRead = fread( data, sizeof(unsigned char), fileSize, fp );
free(data);
if( bytesRead != fileSize )
{
printf( "Error reading file. Unexpected number of bytes read: %lu\n", (unsigned long) bytesRead );
End(fp);
exit(EXIT_FAILURE);
}
return 0;
}
int main( int argc, char ** argv )
{
initialize(argc, argv);
readFile(fp);
/* We now have a pointer to the first byte of data in a copy of the file, have fun
unsigned char * data <--- this is the pointer */
End(fp);
return 0;
}

String / char * concatinate, C

Am trying to open a file(Myfile.txt) and concatenate each line to a single buffer, but am getting unexpected output. The problem is,my buffer is not getting updated with the last concatenated lines. Any thing missing in my code?
Myfile.txt (The file to open and read)
Good morning line-001:
Good morning line-002:
Good morning line-003:
Good morning line-004:
Good morning line-005:
.
.
.
Mycode.c
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
/* Define a temporary variable */
char Mybuff[100]; // (i dont want to fix this size, any option?)
char *line = NULL;
size_t len=0;
FILE *fp;
fp =fopen("Myfile.txt","r");
if(fp==NULL)
{
printf("the file couldn't exist\n");
return;
}
while (getline(&line, &len, fp) != -1 )
{
//Any function to concatinate the strings, here the "line"
strcat(Mybuff,line);
}
fclose(fp);
printf("Mybuff is: [%s]\n", Mybuff);
return 0;
}
Am expecting my output to be:
Mybuff is: [Good morning line-001:Good morning line-002:Good morning line-003:Good morning line-004:Good morning line-005:]
But, am getting segmentation fault(run time error) and a garbage value. Any think to do? thanks.
Specify MyBuff as a pointer, and use dynamic memory allocation.
#include <stdlib.h> /* for dynamic memory allocation functions */
char *MyBuff = calloc(1,1); /* allocate one character, initialised to zero */
size_t length = 1;
while (getline(&line, &len, fp) != -1 )
{
size_t newlength = length + strlen(line)
char *temp = realloc(MyBuff, newlength);
if (temp == NULL)
{
/* Allocation failed. Have a tantrum or take recovery action */
}
else
{
MyBuff = temp;
length = newlength;
strcat(MyBuff, temp);
}
}
/* Do whatever is needed with MyBuff */
free(MyBuff);
/* Also, don't forget to release memory allocated by getline() */
The above will leave newlines in MyBuff for each line read by getline(). I'll leave removing those as an exercise.
Note: getline() is linux, not standard C. A function like fgets() is available in standard C for reading lines from a file, albeit it doesn't allocate memory like getline() does.

how to fix this #0 0xfeea5b41 in strcpy () from /lib/libc.so.1

I want to read a file and store it in a list. I did do that but when I am using gdb I get this error:
#0 0xfeea5b41 in strcpy () from /lib/libc.so.1.
Here is the code:
int
main (int argc, char *argv[])
{
/*declare and initialise variable */
char array[10][150], buffer[150];
//message =(char*)malloc(sizeof(char));
int i = 0;
FILE *fp;
fp = fopen (argv[1], "r");
if (fp == 0)
{
fprintf (stderr, "Input not valid\n");
exit (1);
}
/*stores and prints the data from the string */
int counter = 0;
while (fgets (buffer, 150, fp))
{
strcpy (array[i], buffer);
//printf(" %s",message[i]);
i++;
counter++;
}
fclose (fp);
return 0;
}
There are several things wrong here.
If more than 10 lines are present, you will overrun array, and the strcpy will try copying to an invalid location. I expect that is the cause of the bug.
fopen returns a pointer (so NULL) on error, rather than 0.
You are not checking the return value of fgets; it returns NULL on error.
Incrementing counter and i seems redundant as they both will have the same value.
You have not #included the relevant include files so your C compiler will not pick up the correct function prototypes. You need: #include <stdio.h>, #include <stdlib.h> and #include <string.h>. You would pick this up by compiling with gcc -Wall.

Subtract from an array of char a number of characters

I can't seem to work it out. I am using a .c code that opens a file and reads each line. I would like to save in char*substr 4 characters from the line 9 inside the txt file. The line 5 contains
name=Me She; I would like to have in char*substr just Meli.Need help. THX
Here is the c code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
char str[128];
char str1[128];
if((fp = fopen("/home/folder/file.txt", "r"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}
int lin=0;
while(!feof(fp)) {
if(fgets(str, 126, fp))
printf("%s", str);
if (lin==8)
{
char *c= (char *) malloc(sizeof(char)*strlen(str)+1);
c= strndup(str, strlen(str)-5);?? not working?!!!
printf("d is:",c);
}
lin=lin+1;
}
fclose(fp);
return 0;
}
Your printf is wrong. change it to printf("d is %s\n",c);.
By the way, strdup allocate the memory needed, so you don't have to allocate it yourself. (In fact, you have a memory leak).
You're calling malloc() and then directly overwriting its result with that of calling strndup(), this leaks memory.
Also, the logic in the strndup() call looks wrong. If you want to skip the first 5 characters, you should have str + 5.
If you have strdup(), use:
if (lin==9)
{
char *name = strdup(str + 5);
printf("name is: '%s'\n", name != NULL ? name : "(failed)");
}
Then you should probably break out of the loop. Also note that the pointer name goes out of scope, so it's not available to code outside the loop for instance.

Resources