Read a line using Pointer variable in C - c

[Code]
#include <stdio.h>
//#include <conio.h> // getch()
int main(int argc, char *argv[])
{
char c, *s;
printf("Enter the number...\n");
while ((c=getchar()) != EOF && c != '\n' && c != '\t') {
putchar(c);
*s++ = c; // **What is wrong in here, the code is crashing!!**
}
printf("The number: %s\n", s);
return 0;
}
Output:
c:\works\workout\c>gcc tmp.c -o tmp
c:\works\workout\c>tmp
Enter the number...
434232
4
c:\works\workout\c>
Expected Output:
The actual given input number/string! (e.g 434232 in here)
Expecting output by using 'pointer' only (Without using 'scanf', 'char s[10]' etc.)
Thanks in advance!

First, you have to allocate s because it is a pointer.
Secondly, declare int c instead of char c because the definition of the functions getchar() and putchar() as:
int putchar(int c);
int getchar(void);
Finally, Use s[i] = ... instead of *s++ =.
The complete code (In this code, i use the realloc function for allocating each time you get new value from keyboard):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int c;
char *s = malloc(sizeof(char) + 1);
if (s == NULL)
exit(-1);
printf("Enter the number...\n");
int i = 0;
while ((c=getchar()) != EOF && c != '\n' && c != '\t') {
putchar(c);
s[i] = c;
// re-allocate because the size of s has to increase to store the new value
s = realloc(s, sizeof(char));
if (s == NULL)
exit(-1);
i++;
}
printf("The number: %s\n", s);
return 0;
}

Related

segmentation fault in c about using malloc, and char array pointer

im trying to make a program which reads what we wrote without concerning the memory, and print out what we wrote!
but it goes to segmentation fault (core dump)
#include <stdio.h>
#include <string.h>
int isdigit(char c);
int main()
{
char *input
int length;
printf("Number or Letter\n");
gets(input);
input = (char*)malloc(sizeof(char)*strlen(input));
printf(input[0]);
return 0;
}
To read in an arbitrary long input string, you must use some kind of memory re-allocation when the input string grows beyond the already allocated memory. For instance you could use realloc like this:
#include <stdio.h>
#include <stdlib.h>
#define INCREASE 32
int main(void) {
int c;
int allocated = INCREASE;
int used = 1;
char* in = malloc(allocated*sizeof(char));
if (!in) exit(1);
*in = '\0';
while((c = fgetc(stdin)) != EOF && c != '\n')
{
if (used > (allocated-1))
{
// printf("Realloc\n");
allocated += INCREASE;
char* t = realloc(in, allocated);
if (t)
{
in = t;
}
else
{
free(in);
exit(1);
}
}
in[used-1] = c;
in[used] = '\0';
++used;
}
printf("%s\n", in);
free(in);
return 0;
}

strcat is giving me a segmentation fault error

After verifying that strcat is where the error occurs, I then check the previous example in my assignment. In my previous examples I use strcat(actually strncat) in the same fashion as I do for my following code. I am not too sure.
The purpose of my program is to loop through "string" and remove any occurances the character 'c' from string.
main.c:
char string[100]={0}, c[3];
printf("Enter a String: ");
fgets(string, 100, stdin);
if (string[98] == '\n' && string[99] == '\0') { while ( (ch = fgetc(stdin)) != EOF && ch != '\n'); }
printf("Enter a Char: ");
fgets(c, 2, stdin);
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
rmchr(string, c[0]);
header:
rmchr(char *string, char c)
{
int i=0;
char *word[100];
int s = strlen(string);
for(i=0; i<=(s-2); i++)
{
if(string[i] != c)
{
strcat(word, string[i]);
}
}
}
char *word[100];
It will hold a string in your program so use:
char word[100];
that is, an array of char instead of an array of char *.
Then strcat concatenates to a string but word is not initialized. Make it a string with:
word[0] = '\0';
Then string[i] is a character but strcat needs pointers to character arguments: to use a pointer use &string[i].
Finally the problem in your rmchr function is it has to return something, either through the arguments or via a return statement but it doesn't.
There are more than one point to mention here, like
rmchr() definition should have a return type, maybe void if you're not returning anything.
[FWIW, In that case, I wounder, how you'll make use of the local variable word]
inside rmchr(), word needs to be an array of chars, not char pointers. You need to change char * word[100] to char word[100].
In strcat(), both the arguments, needs to be a pointer. You need to use &string[i], in that case.
The following seems to compile fine but your code doesnt do quite what you said you wanted, "The purpose of my program is to loop through "string" and remove any occurances the character 'c' from string.". the function doesn't remove the character or return a copy of the string with the character excluded. I wrote a function that copies the string after removing the character and returns pointer to it. below is your code a bit modified and under it is my function
//Just a compilable version of your code, not sure if it does what u want
#include <stdio.h>
#include <string.h>
void rmchr(char *string, char c)
{
int i=0;
char word[100];
int s = (int)strlen(string);
for(i=0; i<=(s-2); i++)
{
if(string[i] != c)
{
strcat(word, (char *)(&string[i]));
}
}
}
int main(int argc, const char * argv[]) {
char string[100] = {0}, c[3];
char ch;
printf("Enter a String: ");
fgets(string, 100, stdin);
if (string[98] == '\n' && string[99] == '\0') {
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
}
printf("Enter a Char: ");
fgets(c, 2, stdin);
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
rmchr(string, c[0]);
return 0;
}
There you go, with a demo main
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* rmchr(char *string, char ch)
{
int counter = 0;
int new_size = 0;
char corrected_string[100];
while (string[counter] != '\n' && string[counter] != '\0' && string[counter] != EOF) {
if (string[counter] != ch) {
corrected_string[new_size] = string[counter];
new_size++;
}
counter++;
}
char *new_string = (char *)malloc((new_size+1) * sizeof(char));
for (int j = 0; j <= new_size; j++) {
new_string[j] = corrected_string[j];
}
return new_string;
}
int main(int argc, const char * argv[]) {
char *s = "The char 'c' will be removed";
char *new = rmchr(s, 'c');
printf("%s", new);
return 0;
}

How to fill array of character pointers with arguments taken from scanf?

I'm trying to write a VERY basic shell program in C. The problem I am facing is trying to fill my argv array of character pointers with the words taken from input. When I attempt to print out the contents of the argv array after attempting to fill it using the parse() function below I get a segmentation fault. I know this means that I am probably trying to access part of the argv array that is out of bounds. However, even when supplying only one argument to fill the array, I still get the segfault. The printf call used to print argc returns the correct value for argc based on input, but the second printf call with *argv[0] is the one causing the segfault. I am wondering if my error is in the way I am attempting to print the contents of argv, or if the error is because I am attempting to fill argv incorrectly.
EDIT: I should add that the getword() function takes in a line of text and returns the first word delimited by spaces, and a number of other delimiters. I can post all the delimiters it breaks the words up by if necessary, but I do not think the problem is because of getword().
EDIT 2: Added in the header file and included the #include statement in main.
EDIT 3: Added the getword function under main(), and getword.h below p2.h
Here is p2.h, the header file included in main:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "getword.h"
#include <signal.h>
#define MAXITEM 100
getword.h:
#include <stdio.h>
#include <string.h>
#include <strings.h>
#define STORAGE 255
int getword(char *w);
int parse(char *, char *[]);
Here is the main function :
#include "p2.h"
int main() {
pid_t pid, child_pid;
int argc, inputRedirect;
char *devNull;
devNull = (char *) malloc(10);
strcpy(devNull, "/dev/null");
char *argv[MAXITEM];
char commandLine[STORAGE];
for (;;) {
printf("p2: ");
scanf("%s", commandLine);
argc = parse(commandLine, argv);
printf("argc = %d\n", argc);
if(argc == 0)
continue;
printf("*argv = %s\n", *argv[0]);
child_pid = fork();
if (child_pid < 0) {
printf("Cannot fork! Terminating...");
exit(1);
} else if (child_pid == 0) {
inputRedirect = open(devNull, O_RDONLY);
dup2(inputRedirect, STDIN_FILENO);
close(inputRedirect);
execvp(*argv, argv);
}
else {
for(;;) {
pid = wait(NULL);
if(pid == child_pid)
break;
}
printf("Child's pid is %d\n", child_pid);
}
}
killpg(getpid(), SIGTERM);
printf("p2 Terminated.\n");
exit(0);
}
int parse(char *commandLine, char *argv[]) {
int i, argc = 0;
char *commandPointer = commandLine;
while (*commandPointer != '\0') {
*argv = commandPointer;
argc++;
getword(commandPointer);
}
*commandPointer = '\0';
*argv = '\0';
return argc;
}
getword.c:
#include "getword.h"
#include <stdlib.h>
/*Function Prototypes*/
int tilde(char *p, int i);
int BSFollowedByMetaCharacter(int c, char *w);
int getword(char *w) {
int c;
int index = 0;
/*This while loop removes all leading blanks and whitespace characters
* The if statement then tests if the first character is a new line or
* semicolon metacharacter*/
while ((c = getchar()) == ' ' || c == '\t' || c == '\n' || c == ';') {
if (c == '\n' || c == ';') {
w[index] = '\0';
return 0;
}
}
/*This if statement calls ungetc() to push whatever character was taken
* from the input stream in the previous while loop back to the input
* stream. If EOF was taken from the input stream, ungetc() will return EOF,
* which will then cause getword() to return -1, signalling that it reached
* the End Of File. */
if (ungetc(c, stdin) == EOF)
return -1;
/*This if statement deals with some of the "non-special" metacharacters.
* If one of these metacharacters is pulled from the input stream by getchar(),
* it is stored in w and null-terminated. getword() then returns the length of
* the current string stored in w. If getchar() pulls anything besides one of the
* specified metacharacters from the input stream, it is then returned using ungetc() after
* the if statement.*/
if ((c = getchar()) == '<' || c == '>' || c == '|' || c == '&') {
w[index++] = c;
int d = getchar();
if (c == '>' && d == '>')
w[index++] = d;
else {
ungetc(d, stdin);
}
w[index] = '\0';
return index;
}
ungetc(c, stdin);
/*This while statement handles plain text from the input stream, as well as a few 'special'
* metacharacters. It also ensures that the word scanned is shorter than STORAGE-1 bytes.*/
while ((c = getchar()) != ' ' && c != '<' && c != '>' && c != '|'
&& c != ';' && c != '&' && c != '\t' && c != '\n' && c != '\0'
&& index <= STORAGE - 1) {
if (c == '~') {
int *ip = &index;
index = tilde(&w[index], *ip);
continue;
}/*END IF*/
else if (c == '\\') {
int d = c;
c = getchar();
if (BSFollowedByMetaCharacter(c, w)) {
w[index++] = c;
continue;
} else {
w[index++] = d;
}
}/*END ELSE IF*/
w[index] = c;
index++;
}/*END WHILE*/
ungetc(c, stdin);/*This final ungetc() call is used to push any meta characters*/
w[index] = '\0'; /*used as delimiters back to the input stream, to be retrieved*/
return index; /*at the next call of getword(). */
}/*END getword()*/
int tilde(char *cp, int i) {
int *ip;
ip = &i;
char *p = cp;
char *o;
o = (strcpy(p, getenv("HOME")));
int offset = strlen(o);
*ip = *ip + offset;
return i;
}
int BSFollowedByMetaCharacter(int c, char *w) {
if (c == '~' || c == '<' || c == '>' || c == '|' || c == ';' || c == '&'
|| c == ' ' || c == '\t' || c == '\\') {
return 1;
} else {
return 0;
}
}
The functions in getword.c seems correct. Your problem is in function parse.
To use execvp, contents of argv should be following (input:"hello world"):
argv[0] -> "hello"
argv[1] -> "world"
argv[2] -> NULL
Here, argv is an array of character pointers. But, in parse function, you are treating argv like simple character pointers in here:
*argv = commandPointer;
and here:
*argv = '\0';
Change your parse function into something like this:
int parse(char *commandLine, char *argv[]) {
int argc = 0;
char *commandPointer;
argv[argc++] = commandLine;
do{
commandPointer = (char*)malloc(sizeof(char) * STORAGE);
argv[argc++] = commandPointer;
getword(commandPointer);
}while(*commandPointer != '\0');
argv[argc] = NULL;
return argc;
}
Now, you should free allocated memory after if-else tree like:
for(int i = 0; i < argc; i++) free(argv[i]);

Returning position of any character in the text

The program is designed to return the position of the character in the table s2, in the text of Table S1. In case of failure it will a return -1.
#include <stdio.h>
#include <stdlib.h>
#define RANGE 10
int any(char [], char []);
int main()
{
char s1[RANGE];
char s2[RANGE];
int i,j;
while( (s1[i]=getchar()) != EOF);
while( (s2[j]=getchar()) != EOF);
printf("%d", any(s1, s2));
}
int any(char s1[], char s2[])
{
int i,j;
for(i=0;s1[i]!='\0';i++)
for(j=0;s2[j]!='\0';j++)
{
// for debug
printf("\n%s", s1[i]);
printf("\n%s", s2[j]);
//
if(s1[i]==s2[j])
return i;
}
return -1;
}
It seems to me that the problem occurs when comparing the characters in the tables.
In this case, programme should return -1:
The code has the following problems:
(1) Variables i and j are uninitialized in the code, potentially causing a crash:
int i,j;
while( (s1[i]=getchar()) != EOF);
while( (s2[j]=getchar()) != EOF);
(2) The code also needs to increment the values of i and j as input is being read. Failing to do so will cause all input to be written to s1[0] / s2[0]:
while( (s1[i]=getchar()) != EOF);
while( (s2[j]=getchar()) != EOF);
(3) The terminating ^Z characters should be removed from s1 / s2 (you might also want to remove the 0x0A (line feed)).
(4) The debug statements are outputting characters, not strings, so the printf() format string should be "\n%c", not "\n%s".
Cleaning up your code gives the following working version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RANGE 10
int any(char [], char []);
int main()
{
char s1[RANGE];
char s2[RANGE];
int i,j;
i = j = 0;
while( (s1[i++]=getchar()) != EOF);
s1[i-2] = 0;
while( (s2[j++]=getchar()) != EOF);
s2[j-2] = 0;
printf("%d", any(s1, s2));
}
int any(char s1[], char s2[])
{
int i,j;
for(i=0;s1[i]!='\0';i++)
for(j=0;s2[j]!='\0';j++)
{
// for debug
printf("\n%c", s1[i]);
printf("\n%c", s2[j]);
//
if(s1[i]==s2[j])
return i;
}
return -1;
}
The output for 'aaaa^Z' / 'bbbb^Z' is:
// for debug
printf("\n%s", s1[i]);
printf("\n%s", s2[j]);
%s signifies that the argument is a string (aka char*) but you are actually passing just a char.
Try this:
// for debug
printf("\n%c", s1[i]);
printf("\n%c", s2[j]);

Multiple line input string using fgets

I want to input a multiple-line string using:
fgets(str,100,stdin)
and then output the same string.
For example:
Input:
my name is sandy
i am learning C
and the output should be:
my name is sandy
i am learning C
#include <stdio.h>
#include <string.h>
char *mfgets(char * restrict s, int n, FILE * restrict stream){
int ch, i=0;
if(n<1)return NULL;
if(n==1){
*s = '\0';
return s;
}
while(EOF!=(ch=fgetc(stream))){
s[i++] = ch;
if(i == n - 1) break;
if(ch == '\n'){
char next = fgetc(stream);
if(next == '\n')
break;
else
ungetc(next, stream);
}
}
s[i] = '\0';
return i == 0 ? NULL : s;
}
int main(int argc, char *argv[]){
char str[100];
printf("input (only newline is end)\n");
mfgets(str, 100, stdin);
printf("%s", str);
return 0;
}

Resources