I am trying to write a function that gets multiple lines if ends with \ and just stop if don't have that. I am very new with C so having trouble to do it.
So something like
User input:
Hello, I am blablabla \
I like bablabla \
My favorite color is (stop here)
But in my current function when the user press enter is over and just the first line is saved.
I know that I need to check if in the end have a backslash just keep going and appending, I am just not sure how to do that using getline.
char *getCommand(void){
char* line; //string from user
ssize_t linesize = 0;
//getting command from user if reaches end of file exit or if something went wrong to read file.
if(getline(&line, &linesize, stdin)==-1){
if(feof(stdin)){
exit(0);
}
else{
fprintf(stderr, "Error reading the command: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
return line;
}
What your code is basically doing is reading one line. Few things to note:
feof(stdin) is wrong.
getline() dynamically allocates a string, so you need to free it yourself.
That said, you can implement it this way:
// Returns the number of commands read, -1 if it fails
int getCommand(char **commands, int max_commands)
{
int i, num_cmds = 0;
for (i = 0; i < max_commands; i++) {
char *line = NULL; // This must be initialized to NULL
ssize_t linesize = 0;
if(getline(&line, &linesize, stdin) == -1)
return -1;
line[strcspn(line, "\n")] = '\0'; // Replace \n with a null-terminator
commands[i] = line;
num_cmds++;
if (!strchr(line, '\\')) // if the line doesn't contain a \ then exit
return num_cmds;
}
return num_cmds;
}
commands is an array of strings that will hold your commands. max_commands is the maximum number of commands your array may hold (i.e. its size).
You can use it this way:
int main(void)
{
const int max_commands = 120;
char *commands[max_commands];
int num_cmds = getCommand(commands, max_commands);
if (num_cmds == -1) {
fprintf(stderr, "Error reading commands\n");
return 1;
}
int i;
for (i = 0; i < num_cmds; i++) {
printf("command %d: %s\n", i + 1, commands[i]);
free(commands[i]); // clear memory allocated by getline
}
}
Given your input as an example, here is what you will get:
Hello, I am blablabla \
I like bablabla \
My favorite color is
command 1: Hello, I am blablabla \
command 2: I like bablabla \
command 3: My favorite color is
EDIT: If the \ needs to be at the end of the line, then replace if (!strchr(line, '\\')) with
if (line[strlen(line)-1] != '\\').
You can use this code to solve your problem, I opted to use scanf instead of getline, but the final working is the same:
#include <stdio.h>
#include <stdlib.h>
// Set limit to line
#define LINE_BUFFER 1024
// Get length a string
unsigned int length(const char * str) {
int count = 0;
while (str[count] != '\0') count++;
return count;
}
// Concatenate two strings to a target variable (dest)
int concat(const char * src_1, const char * src_2, char * dest, size_t sizeof_dest) {
// Get lengths from sources
unsigned int src_1_length = length(src_1);
unsigned int src_2_length = length(src_2);
// Calculate minimum length for dest
unsigned int dst_length = src_1_length + src_2_length;
if(sizeof_dest < dst_length)
// Has no minimum length for concatenation
return -1;
int index = 0;
for(int i = 0; i < src_1_length; i++) {
index++;
dest[i] = src_1[i];
}
for(int i = 0; i < src_2_length; i++) dest[index + i] = src_2[i];
return 0;
}
// Read multiline
char * getCommand() {
char * command = NULL;
while(1) {
char line[LINE_BUFFER];
scanf("%[^\n]s", line);
fflush(stdin);
// Get line length
unsigned int line_length = length(line);
// Checking last character
// zero - false
// nonzero - true
char has_slash = line[line_length - 1] == '\\' ? 1 : 0;
// Update slash to breakline
if(has_slash) line[line_length - 1] = '\n';
if(command == NULL) {
command = (char *) malloc(line_length * sizeof(char));
// Copy line to command
for(int i = 0; i < line_length; i++) command[i] = line[i];
} else {
// Concatenate command with current line for command update
unsigned int command_length = length(command);
unsigned int tmp_command_length = line_length + command_length;
char tmp_command[tmp_command_length];
if(concat(command, line, tmp_command, sizeof(tmp_command)) != 0) {
printf("Error in concatenating '%s' with '%s'\n", command, line);
}
// Free memory from old command
free(command);
// Allocating memory for new updated command
command = (char *) malloc(tmp_command_length * sizeof(char));
// Copy command plus current line to new command
for(int i = 0; i < tmp_command_length; i++) command[i] = tmp_command[i];
}
if(!has_slash) break;
}
return command;
}
Click here to access the code repository on Github if you want to improve or fix something. Your collaboration is very welcome.
Quick example of implementation:
Let's assume this is the main file (main.c)
// IMPORTANT: Paste the code above here
// ...
int main() {
char * command = getCommand();
// Print result
printf("\n---- BEGIN ---\n");
printf("\n%s\n", command);
printf("\n---- END ---\n");
// Always clear data allocated in heap memory
free(command);
return 1;
}
Now let's compile the file via terminal, you can use the gcc or clang compilers. In this example I will use clang.
$ clang main.c -o getcommand
(if you are using gcc, just change the clang to gcc)
Run the compiled file:
$ ./getcommand
Right after type your test text
Hello, I am blablabla \
I like blablabla \
My favorite color is
The output should be as follows:
---- BEGIN ---
Hello, I am blablabla
I like blablabla
My favorite color is
---- END ---
I want to create a program in C that takes an arbitrary number of lines of arbitrary length as input and then prints to console the last line that was inputted. For example:
input:
hi
my name is
david
output: david
I figured the best way to do this would be to have a loop that takes each line as input and stores it in a char array, so at the end of the loop the last line ends up being what is stored in the char array and we can just print that.
I have only had one lecture in C so far so I think I just keep setting things up wrong with my Java/C++ mindset since I have more experience in those languages.
Here is what I have so far but I know that it's nowhere near correct:
#include <stdio.h>
int main()
{
printf("Enter some lines of strings: \n");
char line[50];
for(int i = 0; i < 10; i++){
line = getline(); //I know this is inproper syntax but I want to do something like this
}
printf("%s",line);
}
I also have i < 10 in the loop because I don't know how to find the total number of lines in the input which, would be the proper amount of times to loop this. Also, the input is being put in all at once from the
./program < test.txt
command in Unix shell, where test.txt has the input.
Use fgets():
while (fgets(line, sizeof line, stdin)) {
// don't need to do anything here
}
printf("%s", line);
You don't need a limit on the number of iterations. At the end of the file, fgets() returns NULL and doesn't modify the buffer, so line will still hold the last line that was read.
I'm assuming you know the maximum length of the input line.
This one here will surely do the job for you
static char *getLine( char * const b , size_t bsz ) {
return fgets(b, bsz, stdin) );
}
But remember fgets also puts a '\n' character at the end of buffer so perhaps something like this
static char *getLine( char * const b , size_t bsz ) {
if( fgets(b, bsz, stdin) ){
/* Optional code to strip NextLine */
size_t size = strlen(b);
if( size > 0 && b[size-1] == '\n' ) {
b[--size] = '\0';
}
/* End of Optional Code */
return b;
}
return NULL;
}
and your code needs to be altered a bit while calling the getline
#define BUF_SIZE 256
char line[BUF_SIZE];
for(int i = 0; i < 10; i++){
if( getLine(line, BUF_SIZE ) ) {
fprintf(stdout, "line : '%s'\n", line);
}
}
Now it is how ever quite possible to create function like
char *getLine();
but then one needs to define the behavior of that function for instance if the function getLine() allocates memory dynamically then you probably need use a free to de-allocate the pointer returned by getLine()
in which case the function may look like
char *getLine( size_t bsz ) {
char *b = malloc( bsz );
if( b && fgets(b, bsz, stdin) ){
return b;
}
return NULL;
}
depending on how small your function is you can entertain thoughts about making it inline perhaps that's a little off topic for now.
In order to have dynamic number of input of dynamic length, you have to keep on reallocating your buffer when the input is of greater length. In order to store the last line, you have to take another pointer to keep track of it and to stop the input from the terminal you have to press EOF key(ctrl+k). This should do your job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_last_line(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str, *last_str = NULL;
int ch;
size_t len = 0, last_len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(ch=fgetc(fp)){
if(ch == EOF){
break;
}
if(ch == '\n'){
str[len]='\0';
last_len = len;
last_str = realloc(last_str,sizeof(char)*last_len);
last_str[last_len]='\0';
//storing the last line
memcpy(last_str,str,sizeof(char)*last_len);
str = realloc(NULL, sizeof(char)*size);//size is start size
len = 0;
}
else {
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
}
free(str);
return last_str;
}
int main(void){
char *m;
printf("input strings : ");
m = get_last_line(stdin, 10);
printf("last string :");
printf("%s\n", m);
free(m);
return 0;
}
I am a beginner in coding and having difficulty trying to take input from both command line as well as console(STDIN). my program is supposed to search and replace a group of characters from a string. For example, concatenate cat gat : the output must be congatenate!
This is my code so far!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*Function to replace a string with another string*/
char *rep_str(const char *s, const char *old, const char *new1)
{
char *ret;
int i, count = 0;
int newlen = strlen(new1);
int oldlen = strlen(old);
for (i = 0; s[i] != '\0'; i++)
{
if (strstr(&s[i], old) == &s[i])
{
count++;
i += oldlen - 1;
}
}
ret = (char *)malloc(i + count * (newlen - oldlen));
if (ret == NULL)
exit(EXIT_FAILURE);
i = 0;
while (*s)
{
if (strstr(s, old) == s) //compare the substring with the newstring
{
strcpy(&ret[i], new1);
i += newlen; //adding newlength to the new string
s += oldlen;//adding the same old length the old string
}
else
ret[i++] = *s++;
}
ret[i] = '\0';
return ret;
}
int main(int argc, char*agrv[])
{
char mystr[100], c[10], d[10];
scanf("%s", mystr);
scanf(" %s",c);
scanf(" %s",d);
char *newstr = NULL;
newstr = rep_str(mystr, c,d);
printf("%s\n", newstr);
free(newstr);
return 0;
}
as for now, it shows correct output for either console input or commandline input, bur not both!
kindly suggest the changes to be made!
You can have a check on the variable argc of function int main().
// Path of executable file is passed by default so value of 'argc' will be at least 1
if(argc > 1)
{
// do stuff to work on input from command line
}else{
// do stuff to work on input from STDIN
}
Instead of trying to parse input file through argc and argv, simply pass all the input file through stdin. This means that you will always use scanf to read input data.
At command line you will need to call using pipes, something like this:
$ cat file.txt | yourprogram
I am new to C but I am trying to write a function that returns a line from a file depending on the parameter used. It will return the last line that contains that parameter. I think it's better explained using an example:
Here is the contents of the file:
1 one onehello
2 two twohello
3 one threehello
So, if I call the function like this:
lineContaining("one")
It should return "one threehello"
Here is what I have so far, it also includes a main function that tests the function:
char *readStringedCommand(char *str1)
{
int size = 1024;
char *buffer = malloc(size);
char *result = malloc(size);
FILE *fp;
fp = fopen("test.txt", "r");
while(fgets(buffer, 1024, fp)) //get a line from a file
{
printf("while1 entered: %s", buffer);
int i = 0;
int j = 0;
int k = 0;
while(buffer[i] != '\n') //read all the way to the end of a line
{
printf("while2 entered: %s", buffer+i);
k = i;
while(buffer[k]==str1[j]) //while two characters match
{
printf("while3 entered");
k++;
j++;
strcat(result, buffer+k); //append the character to the result
if(str1[j] = '\0') //if the next character of str1 is the last one
{
strncat(result, buffer+k, 20); //append the rest of buffer to the result
return result;
printf("result = %s", result);
}
}
result[0] = '\0'; //clear result for the next line
j = 0; //set str1's position to 0
k = 0;
i++;
}
}
return "errorrrrrr";
}
int main(int argc, const char* argv[])
{
int num1 = 1;
char str1[] = "one onehello";
int num2 = 2;
char str2[] = "two twohello";
int num3 = 3;
char str3[] = "one threehello";
hwrite(num1, str1); //a function I made that writes a line to a file
hwrite(num2, str2);
hwrite(num3, str3);
printf("%s", readStringedCommand("one"));
return 0;
}
Okay, the function gives me an error:
while1 entered: 1 one onehello
while2 entered: 1 one onehello
while2 entered: one onehello
while2 entered: one onehello
Segmentation fault (core dumped)
Considering it gives me the error at the third while loop, I think the problem is there. I unfortunately don't know what is wrong here. I am sure there are more errors after that point but this one is confusing me.
MY QUESTIONS:
How do I fix this segmentation error?
The code is obviously very ugly but I suck at C. Is there a better way to solve this question?
Thanks for reading all of this and I would appreciate some help. =(
EDIT: After fixing some errors suggested by you guys, I no longer get the segmentation error. The function returns " onehello" instead, which is wrong. It should return "one threehello". But I am making progress, and for that I am thankful.
if(str1[j] = '\0')
should be
if(str1[j] == '\0')
you probably want to compare values
the loop while(buffer[i] != '\n') might not exit if your file is missing a newline character, what might happen in the last line of in .txt file.
So if I understand your problem correctly, your goal can be achieved in a much simpler way:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *readStringedCommand(char *str1)
{
int size = 1024;
char *buffer = malloc(size);
char *result = malloc(size);
/* Check allocations */
if (!buffer || !result) {
fprintf(stderr, "Allocation failure, exiting.\n");
exit(EXIT_FAILURE);
}
result[0] = 0; // 0-terminate result
FILE *fp;
fp = fopen("test.txt", "r");
/* Check whether file was opened successfully */
if (!fp) {
fprintf(stderr, "Couldn't open file.\n");
exit(EXIT_FAILURE);
}
while(fgets(buffer, size, fp)) //get a line from a file
{
if (strstr(buffer, str1)) { // Check whether the line contains the needle
strcpy(result, buffer); // Copy the line if it does
}
}
// close file
fclose(fp);
// Free memory we don't need anymore
free(buffer);
// Now, what if no line contained the needle?
if (result[0] == 0) {
// Hmm, maybe
free(result);
return NULL; // ?
} else {
return result;
}
}
Just use strstr from the standard library to check whether str1 is contained in each line, copy each line that contains it to result, ignore the others. Then at the end, result contains the last line that contained str1 - if any.
If you don't want the entire line, but only the part starting at the first occurrence of str1, capture the pointer that strstr returns, and use that as the source for the strcpy:
char *needle;
if ((needle = strstr(buffer, str1))) {
strcpy(result, needle);
}
I have a text file as data.txt and I want to delete the last members of each line:
Here's the text file:
2031,2,0,0,0,0,0,0,54,0,
2027,2,0,0,0,0,0,0,209,0,
2029,2,0,0,0,0,0,0,65,0,
2036,2,0,0,0,0,0,0,165,0,
I would like to delete so it becomes:
2031,2,0,0,0,0,0,0,
2027,2,0,0,0,0,0,0,
2029,2,0,0,0,0,0,0,
2036,2,0,0,0,0,0,0,
I'm working in C but as the numbers can have two or three digits, I'm not sure how to do this.
A couple of uses of strrchr() can do the job:
#include <string.h>
void zap_last_field(char *line)
{
char *last_comma = strrchr(line, ',');
if (last_comma != 0)
{
*last_comma = '\0';
last_comma = strrchr(line, ',');
if (last_comma != 0)
*(last_comma + 1) = '\0';
}
}
Compiled code that seems to work. Note that given a string containing a single comma, it will zap that comma. If you don't want that to happen, then you have to work a little harder.
Test code for zap_last_field()
#include <string.h>
extern void zap_last_field(char *line);
void zap_last_field(char *line)
{
char *last_comma = strrchr(line, ',');
if (last_comma != 0)
{
*last_comma = '\0';
last_comma = strrchr(line, ',');
if (last_comma != 0)
*(last_comma + 1) = '\0';
}
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *line = malloc(4096);
if (line != 0)
{
while (fgets(line, 4096, stdin) != 0)
{
printf("Line: %s", line);
zap_last_field(line);
printf("Zap1: %s\n", line);
}
free(line);
}
return(0);
}
This has been vetted with valgrind and is OK on both the original data file and the mangled data file listed below. The dynamic memory allocation is there to give valgrind the maximum chance of spotting any problems.
I strongly suspect that the core dump reported in a comment happens because the alternative test code tried to pass a literal string to the function, which won't work because literal strings are not generally modifiable and this code modifies the string in situ.
Test code for zap_last_n_fields()
If you want to zap the last couple of fields (a controlled number of fields), then you'll probably want to pass in a count of the number of fields to be zapped and add a loop. Note that this code uses a VLA so it requires a C99 compiler.
#include <string.h>
extern void zap_last_n_fields(char *line, size_t nfields);
void zap_last_n_fields(char *line, size_t nfields)
{
char *zapped[nfields+1];
for (size_t i = 0; i <= nfields; i++)
{
char *last_comma = strrchr(line, ',');
if (last_comma != 0)
{
zapped[i] = last_comma;
*last_comma = '\0';
}
else
{
/* Undo the damage wrought above */
for (size_t j = 0; j < i; j++)
*zapped[j] = ',';
return;
}
}
zapped[nfields][0] = ',';
zapped[nfields][1] = '\0';
}
#include <stdio.h>
int main(void)
{
char line1[4096];
while (fgets(line1, sizeof(line1), stdin) != 0)
{
printf("Line: %s", line1);
char line2[4096];
for (size_t i = 1; i <= 3; i++)
{
strcpy(line2, line1);
zap_last_n_fields(line2, i);
printf("Zap%zd: %s\n", i, line2);
}
}
return(0);
}
Example run — using your data.txt as input:
Line: 2031,2,0,0,0,0,0,0,54,0,
Zap1: 2031,2,0,0,0,0,0,0,54,
Zap2: 2031,2,0,0,0,0,0,0,
Zap3: 2031,2,0,0,0,0,0,
Line: 2027,2,0,0,0,0,0,0,209,0,
Zap1: 2027,2,0,0,0,0,0,0,209,
Zap2: 2027,2,0,0,0,0,0,0,
Zap3: 2027,2,0,0,0,0,0,
Line: 2029,2,0,0,0,0,0,0,65,0,
Zap1: 2029,2,0,0,0,0,0,0,65,
Zap2: 2029,2,0,0,0,0,0,0,
Zap3: 2029,2,0,0,0,0,0,
Line: 2036,2,0,0,0,0,0,0,165,0,
Zap1: 2036,2,0,0,0,0,0,0,165,
Zap2: 2036,2,0,0,0,0,0,0,
Zap3: 2036,2,0,0,0,0,0,
It also correctly handles a file such as:
2031,0,0,
2031,0,
2031,
2031
,