why fgets() not working here? - pointers

In the below code scanf() is working for getting the name from the user but fgets() is not working pls someone help me to understand why it's not working
#include <stdio.h>
#include <stdlib.h>
typedef struct university{
int roll_no;
char name[16];
}uni;
int main()
{
uni *ptr[5],soome;char i,j=0;
for(i=0;i<5;i++)
{
ptr[i]=(uni*)calloc(1,20);
if(ptr[i]==NULL)
{
printf("memory allocation failure");
}
printf("enter the roll no and name \n");
printf("ur going to enter at the address%u \n",ptr[i]);
scanf("%d",&ptr[i]->roll_no);
//scanf("%s",&ptr[i]->name);
fgets(&ptr[i]->name,16,stdin);
}
while(*(ptr+j))
{
printf("%d %s\n",ptr[j]->roll_no,ptr[j]->name);
j++;
}
return 0;
}

First of all, fgets(char *s, int n, FILE *stream) takes three argument: a pointer s to the beginning of a character array, a count n, and an input stream.
In the original application you used the address operator & to get the pointer not to the first element of the name[16] array, but to something else (to use the address operator, you should have referenced the first char in the array: name[0]).
You use a lot of magic numbers in your application (e.g. 20 as the size of the uni struct). In my sample I'm using sizeof as much as possible.
Given that you use calloc, I've used the fact that the first parameter is the number of elements of size equal to the second parameter to preallocate all the five uni struct at once.
Final result is:
#include <stdio.h>
#include <stdlib.h>
#define NUM_ITEMS (5)
#define NAME_LENGTH (16)
typedef struct university{
int roll_no;
char name[NAME_LENGTH];
} uni;
int main()
{
uni *ptr;
int i;
ptr = (uni*)calloc(NUM_ITEMS, sizeof(uni));
if(NULL == ptr) {
printf("memory allocation failure");
return -1;
}
for(i=0; i<NUM_ITEMS; i++) {
printf("enter the roll no and name \n");
printf("You're going to enter at the address: 0x%X \n",(unsigned int)&ptr[i]);
scanf("%d",&ptr[i].roll_no);
fgets(ptr[i].name, NAME_LENGTH, stdin);
}
for(i=0; i<NUM_ITEMS; i++) {
printf("%d - %s",ptr[i].roll_no,ptr[i].name);
}
free(ptr);
return 0;
}
Note: I've added a call to free(ptr); to free the memory allocated by calloc at the end of the application and a different return code if it's not possible to allocate the memory.

Related

How does one use qsort to sort a char containing pathnames/files based on their bytes?

I basically wrote a code in which I take two command line arguments one being the type of file that I want to search in my directory and they other being the amount I want(which is not implemented yet, but I can fix that)
The code is like so:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define sizeFileName 500
#define filesMax 5000
int cmpfunc( const void *a, const void *b) {
return *(char*)a + *(char*)b;
}
int main( int argc, char ** argv) {
FILE * fp = popen( "find . -type f", "r");
char * type = argv[1];
char * extension = ".";
char* tExtension;
tExtension = malloc(strlen(type)+1+4);
strcpy(tExtension, extension);
strcat(tExtension, type);
// printf("%s\n",tExtension);
int amount = atoi(argv[2]);
//printf("%d\n",amount);
char buff[sizeFileName];
int nFiles = 0;
char * files[filesMax];
while(fgets(buff,sizeFileName,fp)) {
int leng = strlen(buff) - 1;
if (strncmp(buff + leng - 4, tExtension, 4) == 0){
files[nFiles] = strndup(buff,leng);
//printf("\t%s\n", files[nFiles]);
nFiles ++;
}
}
fclose(fp);
printf("Found %d files\n", nFiles);
long long totalBytes = 0;
struct stat st;
// sorting based on byte size from greatest to least
qsort(files, (size_t) strlen(files), (size_t) sizeof(char), cmpfunc);
for(int i = 0;i< nFiles; i ++) {
if(0!= stat(files[i],&st)){
perror("stat failed:");
exit(-1);
}
totalBytes += st.st_size;
printf("%s : %ld\n",files[i],st.st_size);
}
printf("Total size: %lld\n", totalBytes);
// clean up
for(int i = 0; i < nFiles ; i ++ ) {
free(files[i]);
}
return 0;
}
So far I have every section set up properly, upon running the code say $./find ini 5, it would print out all the ini files followed by their byte size(it's currently ignore the 5). However, for the qsort(), I'm not exactly sure how I would sort the contents of char * files as while it holds the pathnames, I had to use stat to get the byte sizes, how would I print out a sorted version of my print statements featuring the first statement being the most bytes and finishes at the least bytes?
If we suppose your input is valid, your question could be simplified with:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define filesMax 5000
int cmpfunc(const void const *a, const void *b) { return *(char *)a + *(char *)b; }
int main(void) {
int nFiles = 4;
char *files[filesMax] = {"amazing", "hello", "this is a file", "I'm a bad file"};
qsort(files, strlen(files), sizeof(char), cmpfunc);
for (int i = 0; i < nFiles;; i++) {
printf("%s\n", files[i]);
}
}
If you compile with warning that give you:
source_file.c:11:23: warning: incompatible pointer types passing 'char *[5000]' to parameter of type 'const char *' [-Wincompatible-pointer-types]
qsort(files, strlen(files), sizeof(char), cmpfunc);
^~~~~
qsort() expect the size of your array (or in your case a subsize) and it's also expect the size of one element of your array. In both you wrongly give it to it. Also, your compare function doesn't compare anything, you are currently adding the first bytes of both pointer of char, that doesn't make a lot of sense.
To fix your code you must write:
qsort(files, nFiles, sizeof *files, &cmpfunc);
and also fix your compare function:
int cmpfunc_aux(char * const *a, char * const *b) { return strcmp(*a, *b); }
int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }
also size should be of type size_t:
size_t nFiles = 0;
Don't forget that all informations about how to use a function are write in their doc.
how would I print out a sorted version of my print statements featuring the first statement being the most bytes and finishes at the least bytes?
Your code don't show any clue that your are trying to do that, you are currently storing name file and only that. How do you expect sort your file with an information you didn't acquired ?
However, that simple create a struct that contain both file name and size, acquire information needed to sort it and sort it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <inttypes.h>
struct file {
off_t size;
char *name;
};
int cmpfunc_aux(struct file const *a, struct file const *b) {
if (a->size > b->size) {
return -1;
} else if (a->size < b->size) {
return 1;
} else {
return 0;
}
}
int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }
#define filesMax 5000
int main(void) {
size_t nFiles = 4;
struct file files[filesMax] = {{42, "amazing"},
{21, "hello"},
{168, "this is a file"},
{84, "I'm a bad file"}};
qsort(files, nFiles, sizeof *files, &cmpfunc);
for (size_t i = 0; i < nFiles; i++) {
printf("%s, %" PRId64 "\n", files[i].name, (intmax_t)files[i].size);
}
}
The function cmpfunc() provided adds the first character of each string, and that's not a proper comparison function (it should give a opposite sign value when you switch the parameters, e.g. if "a" and "b" are the strings to compare, it adds the first two characters of both strings, giving 97+98 == 195, which is positive on unsigned chars, then calling with "b" and "a" should give a negative number (and it again gives you 98 + 97 == 195), more on, it always gives the same result ---even with signed chars--- so it cannot be used as a sorting comparator)
As you are comparing strings, why not to use the standard library function strcmp(3) which is a valid comparison function? It gives a negative number if first string is less lexicographically than the second, 0 if both are equal, and positive if first is greater lexicographically than the second.
if your function has to check (and sort) by the lenght of the filenames, then you can define it as:
int cmpfunc(char *a, char *b) /* yes, you can define parameters as char * */
{
return strlen(a) - strlen(b);
}
or, first based on file length, then lexicographically:
int cmpfunc(char *a, char *b)
{
int la = strlen(a), lb = strlen(b);
if (la != lb) return la - lb;
/* la == lb, so we must check lexicographycally */
return strcmp(a, b);
}
Now, to continue helping you, I need to know why do you need to sort anything, as you say that you want to search a directory for a file, where does the sorting take place in the problem?

reason for runtime error in my c program &?

#include<stdio.h>
main()
{char *names[4];
int i,a;
printf("ënter the guests names\n");
for(i=0;i<=3;i++)
{
scanf("%s",names[i]);
}
char *yourname;
printf("\nenter your name ");
scanf("%c",yourname);
for(i=0;i<=3;i++)
{a=strcmp(names[i],yourname);
if(a==0)
printf("\nwelcome");
break;
}
if(a!=0)
printf("\naccess denied");
return 0;
}
this is a program to check your entry in a show. first we give permitted names & then it asks your name ,it compares your name with the names in the guest list.
i m getting runtime error, plz tell me the correction.i want to use pointers to string so plz suggest correction in the existing program
when i run this program in devc++ after entering first name it gives program.exe stopped working.
The code will be like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *names[4];
int i,a;
printf("ënter the guests names\n");
for(i=0;i<=3;i++) {
names[i] = (char*) malloc(100 * sizeof(char));
scanf("%s", names[i]);
}
char yourname[100];
printf("\nenter your name ");
scanf("%s",yourname);
for(i=0;i<=3;i++) {
a = strcmp(names[i], yourname);
if (a == 0) break;
}
if (a==0)
printf("\nwelcome");
else printf("\naccess denied");
for(i=0;i<=3;i++)
free(names[i]);
return 0;
}
Your code have to be formated so we can give you a better answer.
Now, use gets to take your input, verify the guest match with your name inside the for loop, stop the loop when a match is found.
#include<stdio.h>
#include<string.h>
int main()
{
char names[4][20];
int i = 0;
int a = 0;
printf("Enter guests names: \n");
for(i=0; i<3; i++)
{
gets(names[i]);
}
char yourname[20];
printf("\n Enter your name ");
gets(yourname);
printf("\n Verify access right:");
for(i=0; i<3; i++)
{
a=strcmp(names[i], yourname);
if(a==0)
{
printf("\n welcome");
break;
}
else
{
printf("\n access denied");
}
}
return 0;
}
Although this looks like a homework assignment.

seg fault / pointer assistance

so i know the bases of programming, i have a decent amount of experience with java, but im learning C for school right now. I still dont completely understand the whole pointer aspect, which is what im sure caused the fault. This program works fine when run on my computer, but when i try and run it on my schools unix shell it gives me a seg fault. if someone could please explain to me why or how ive misused hte pointers, that would help me greatly.
//Matthew Gerton
//CS 222 - 002
//10/10/14
//HW Six
//libraries
#include<stdio.h>
#include<string.h>
#define max_Length 256
//prototypes
void decode(char *a, char *b);
void trimWhite(char *a);
void encode(char *a, char *b);
int main(void)
{
//character arrays
char coded[max_Length], decoded[max_Length];
//decode the sample phrase
char sample[] = {'P','H','H','W','D','W','C','R','R','F','D','Q','F','H','O','H','G','J',
'R','W','R','P','H','W','U','R','K','R','W','H','O','U','R','R','P','I','R','X','U'};
decode(sample, decoded);
//scans a user input string to decode, and decodes it
printf("\nPlease enter a phrase to decode: ");
gets(coded);
trimWhite(coded);
decode(coded, decoded);
//scans a user input phrase to encode
printf("\nPlease enter a phrase to encode: ");
gets(coded);
trimWhite(coded);
encode(coded, decoded);
}
//removes any spaces from the input
void trimWhite(char *a)
{
char temp[max_Length];
int z=0, y=0;
while(a[z]!='\0')
{
if(a[z]!=' ')
{
temp[y]=a[z];
y++;
}
z++;
}
temp[y] = '\0';
strcpy(a,temp);
}
//decodes any phrase
void decode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
while(a[i]!='\0')
{
n=(int)a[i];
if(n<97)
n=n+32;
if(n<=99)
n=n+23;
else
n = n-3;
b[i]= (char) n;
i++;
}
b[i]='\0';
printf("Coded message: %s\n", a);
printf("Decoded message: %s\n", b);
}
//codes an input phrase
void encode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
strcpy(b,a);
while(a[i]!='\0')
{
n=(int)a[i];
if(n<97)
a[i] = (char)(n+32);
if((n>120)
a[i] = (char)(n-23);
else
a[i] = (char)((n+3);
i++;
}
printf("Coded message: %s\n", a);
}
Your main problem is here:
char sample[] = {'P','H','H', /* snip */ ,'R','X','U'};
The sample[] array is not zero-terminated which may cause the decode() function to copy many more characters than intended, thus overwriting other variables. You need to explicitly add a terminating zero when using an initializer-list:
char sample[] = {'P','H','H', /* ... */ ,'R','X','U',0};
Or you can initialize the array using a string literal, which does include a terminating zero:
char sample[] = "PHHWDWCRRFDQFHOHGJRWRPHWURKRWHOURRPIRXU";
You should probably read "Why is the gets function dangerous".
...
void decode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
Also note that the size of the array is lost when it is passed to a function. The function only receives a pointer to its first element. The memset() call above will only zero sizeof(char*) bytes (usually 4 or 8). This doesn't matter though because, as far as I can tell, you only need to zero the first byte. You could simply write:
b[0] = 0;

gcc: /home/jamie/aws/btree_int.c|28|error: request for member ‘btree_start’ in something not a structure or union|

This code:
#include <stdlib.h>
#include <stdio.h>
int j_btree_create (int fn_initial_nodes);
typedef struct {
int depth;
int value;
void *item;
void *left_pointer;
void *right_pointer;
} j_btree_node_int;
typedef struct {
int nodes;
int available_nodes;
int btree_extension;
} j_btree_descriptor_int;
int j_btree_create (int fn_initial_nodes) {
int *free_btree_node;
int loop_counter;
j_btree_descriptor_int *btree_start;
btree_start = (j_btree_descriptor_int *) malloc (((sizeof(j_btree_node_int) + sizeof(free_btree_node)) * fn_initial_nodes) + sizeof(j_btree_descriptor_int));
printf ("btree_start: " . btree_start);
/* *btree_start.nodes = fn_initial_nodes;
*btree_start.available_nodes = fn_initial_nodes;
*btree_start.extension = NULL; */
for (loop_counter = 0; loop_counter < fn_initial_nodes; loop_counter++) {
printf ("loop_test:" . loop_counter);
}
}
Produces this error:
/home/jamie/aws/btree_int.c||In function ‘j_btree_create’:|
/home/jamie/aws/btree_int.c|28|error: request for member ‘btree_start’ in something not a structure or union|
/home/jamie/aws/btree_int.c|33|error: request for member ‘loop_counter’ in something not a structure or union|
||=== Build finished: 2 errors, 0 warnings ===|
When compiled with CodeBlocks. I have not managed to find an exact answer to my problem (I have looked), does anyone know roughly what I am doing wrong? Probably more than one thing given I am fairly new to C.
printf ("btree_start: " . btree_start);
This is not how the things are done in c. There's no . concatenation operator and you do not concatenate strings (pointers to characters) and pointers to structures. If you want to print out the pointer, it's
printf("btree_start: %p\n",btree_start);
For the loop counter it's
printf("loop_test: %d",loop_counter);

Error writing and reading a structure from PIPE

I have a client server program where client writes a command on PIPE for server. While reading the command from Server it reads only first char of command and throws error. Can anyone help me with this?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/wait.h>
#include <mqueue.h>
#include <sys/stat.h>
#include "Functions.h"
#define MSGBUFFER_SIZE 50000
pid_t serverPid;
pid_t clientPid;
typedef struct msgbuf {
int messageLength;
int messageType;
char messageText[MSGBUFFER_SIZE];
} Message_buf;
int writePIPE(int fd, Message_buf *inputMessage){
printf("\n In write pipe message length :%d",inputMessage->messageLength);
printf("\n In write pipe message Data :%s",inputMessage->messageText);
ssize_t n=write(fd,inputMessage,inputMessage->messageLength);
printf("\n Size :%d", n);
return n;
}
ssize_t readPIPE(int fd, Message_buf *outputMessage)
{
ssize_t len;
ssize_t n;
if((n=read(fd,outputMessage,sizeof(outputMessage)))==0)
{
printf("\n Error");
return 0;
}
if((len=outputMessage->messageLength)>0)
{
printf("\n Length ---->:%d",len);
if((n=read(fd,outputMessage->messageText,strlen(outputMessage->messageText)))!=len)
printf("\n ERRRRROR expected %d got %d",len,n);
}
//printf("\n In Read PIPE: %s",outputMessage->messageText);
return len;
}
void Server(int readfd,int writefd)
{
Message_buf server_MessageBuf;
ssize_t length;
if((length=readPIPE(readfd,&server_MessageBuf))==0)
{
printf("\n End of file while reading pathname");
}
//server_MessageBuf.messageText[length]='\0';
printf("\n LENGTH :%d",server_MessageBuf.messageLength);
printf("\n Printing in server: %s\n",server_MessageBuf.messageText);
}
void Client(int readfd,int writefd)
{
char inputFileName[MAX_SIZE];
char inputOperation[MAX_SIZE];
char *cCommandInput = NULL;
char *fileOperation = NULL;
char *operation = (char *) malloc(MAX_SIZE);
int commandValidateStatus = 0;
int commandInterpretationStatus=0;
Message_buf client_MessageBuf;
for(;;)
{
while(1)
{
cCommandInput = acceptInput();
fileOperation = (char *) malloc(sizeof(cCommandInput));
strcpy(fileOperation,cCommandInput);
/**Function call to determine operation read/delete/exit/invalid choice and filename*****/
commandInterpretationStatus = interpretCommand(cCommandInput,
inputOperation, inputFileName);
operation = inputOperation;
/**Function call to validate the input command******/
commandValidateStatus = validateCommand(
commandInterpretationStatus, inputOperation, inputFileName);
if(commandValidateStatus==-1)
{
printf("\n Invalid Operation");
}
/*Exit command entered***/
if (commandValidateStatus == 1)
{
/*Code to clear resources */
kill(serverPid,SIGKILL);
kill(clientPid,SIGKILL);
exit(0);
}
/***Read or Delete****/
if (commandValidateStatus == 2 || commandValidateStatus == 3)
{
printf("\n Read or Delete\n");
strcpy(client_MessageBuf.messageText,fileOperation);
client_MessageBuf.messageLength=strlen(fileOperation);
client_MessageBuf.messageType=1;
if((writePIPE(writefd,&client_MessageBuf))<0)
{
printf("\n Error writing on client side ");
}
//read(readfd,*client_MessageBuf,sizeof(client_MessageBuf));
//printf("\n Reding server responsed");
//printf("%s",client_MessageBuf.messageText);
}
}
}
}
int main()
{
int pipe1[2],pipe2[2];
pipe(pipe1);
pipe(pipe2);
pid_t pid;
pid=fork();
serverPid=pid;
if(pid==0)
{
/*Call Server*/
close(pipe1[1]);
close(pipe2[0]);
Server(pipe1[0], pipe2[1]);
}
else
{
close(pipe1[0]);
close(pipe2[1]);
Client(pipe2[0],pipe1[1]);
}
return 0;
}
It looks like the code writes and reads struct msgbuf incorrectly:
typedef struct msgbuf {
int messageLength;
int messageType;
char messageText[MSGBUFFER_SIZE];
} Message_buf;
// ...
strcpy(client_MessageBuf.messageText,fileOperation);
client_MessageBuf.messageLength=strlen(fileOperation);
client_MessageBuf.messageType=1;
if((writePIPE(writefd,&client_MessageBuf))<0)
// ....
int writePIPE(int fd, Message_buf *inputMessage){
printf("\n In write pipe message length :%d",inputMessage->messageLength);
printf("\n In write pipe message Data :%s",inputMessage->messageText);
ssize_t n=write(fd,inputMessage,inputMessage->messageLength);
printf("\n Size :%d", n);
return n;
}
The above pieces that write struct msgbuf only write the first messageLength bytes of the structure which doesn't include the length of messageLength and messageType members, i.e. it truncates the object.
When reading:
ssize_t readPIPE(int fd, Message_buf *outputMessage)
{
// ...
if((n=read(fd,outputMessage,sizeof(outputMessage)))==0)
It reads only sizeof(outputMessage) bytes, which is the size of the pointer, not the object. Even if you fix it by changing it to sizeof(*outputMessage) that won't do enough, since that would expect to read the complete object whereas the writing piece truncates the object.
A good start to fix it would be to split the message into two parts: header and payload. The header is a structure of a fixed size, e.g.:
typedef struct {
int messageType;
int payloadLength;
} MessageHeader;
The payload is a variable-length part following the header. This way it would first write the entire header object into the pipe followed by payloadLength bytes of payload. When reading it would first read again the entire header and then read exactly payloadLength bytes.
Also note, that read() and write() calls may read or write less then asked, so that case needs to be explicitly handled by keeping reading or writing until the exact number of bytes has been processed.

Resources