0

I'm looking to copy the FIRST line from a LONG string P into a buffer

I have no idea how to make it.

while (*pros_id != '/n'){
   *pros_id_line=*pros_id;
   pros_id++;
   pros_id_line++;
}

And tried

fgets(pros_id_line, sizeof(pros_id_line), pros_id);

Both are not working. Can I get some help please?

Maroun
  • 94,125
  • 30
  • 188
  • 241
JohnnyF
  • 1,053
  • 4
  • 16
  • 31

4 Answers4

2

Note, as Adriano Repetti pointed out in a comment and an answer, that the newline character is '\n' and not '/n'.

Your initial code can be fixed up to work, provided that the destination buffer is big enough:

while (*pros_id != '\n' && *pros_id != '\0')
   *pros_id_line++ = *pros_id++;
*pros_id_line = '\0';

This code does not include the newline in the copied buffer; it is easy enough to add it if you need it.

One advantage of this code is that it makes a single pass through the data up to the newline (or end of string). An alternative makes two passes through the data, one to find the newline and another to copy to the newline:

if ((end = strchr(pros_id, '\n')) != 0)
{
    memmove(pros_id_line, pros_id, end - pros_id);
    pros_id_line[end - pros_id] = '\0';
}

This ensures that the string is null-terminated; again, it omits the newline, and assumes there is enough space in the pros_id_line buffer for the data. You have to decide what is the correct behaviour when there is no newline in the buffer. It might be sufficient to copy the buffer without the newline into the target area, or you might prefer to report a problem.

You can use strncpy() instead of memmove() but it has a more complex loop condition than memmove() — it has to check for a null byte as well as the count, whereas memmove() only has to check the count. You can use memcpy() instead of memmove() if you're sure there's no overlap between source and target, but memmove() always works and memcpy() sometimes doesn't (though only when the source and target areas overlap), and I prefer reliability over possible misbehaviour.

Note that setting a buffer to zero before copying a string to it is a waste of energy. The parts that you're about to overwrite with data didn't need to be zeroed. The parts that you aren't going to overwrite with data didn't need to be zeroed either. You should know exactly which byte needs to be zeroed, so why waste the time on zeroing anything except the one byte that needs to be zeroed?

(One exception to this is if you are dealing with sensitive data and are concerned that some function that your code will call may deliberately read beyond the end of the string and come across parts of a password or other sensitive data. Then it may be appropriate to wipe the memory before writing new data to it. On the whole, though, most people aren't writing such code.)

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

New line is \n not /n anyway I'd use strchar for this:

char* endOfFirstLine = strchr(inputString, '\n');
if (endOfFirstLine != NULL)
{
    strncpy(yourBuffer, inputString,
        endOfFirstLine - inputString);
}
else // Input is one single line
{
    strcpy(yourBuffer, inputString);
}

With inputString as your char* multiline string and inputBuffer (assuming it's big enough to contain all data from inputString and it has been zeroed) as your required output (first line of inputString).

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • 1
    Null termination? `strncpy()` doesn't! – Jonathan Leffler Aug 04 '14 at 07:28
  • @JonathanLeffler assuming it has been zeroed, I'll add that – Adriano Repetti Aug 04 '14 at 07:28
  • 2
    Never assume a buffer has been zeroed; it is a waste of effort, all else apart. Why write zeros where you're about to write information, and why write zeros where you aren't about to write information? – Jonathan Leffler Aug 04 '14 at 07:29
  • @JonathanLeffler well primary because gain is such small (and in this case if performance is an issue OP may even directly use `memcpy` instead of `strncpy` that it's times faster because implementation without NUL check is different and quicker) but also because it'll help me during debugging so if I don't have a measured reason to avoid `memset` then I'll always use it. – Adriano Repetti Aug 04 '14 at 08:59
1

If you're going to be doing a lot of reading from long text buffers, you could try using a memory stream, if you system supports them: https://www.gnu.org/software/libc/manual/html_node/String-Streams.html

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

static char buffer[] = "foo\nbar";

int
main()
{
    char arr[100];
    FILE *stream;

    stream = fmemopen(buffer, strlen(buffer), "r");
    fgets(arr, sizeof arr, stream);
    printf("First line: %s\n", arr);
    fgets(arr, sizeof arr, stream);
    printf("Second line: %s\n", arr);
    fclose (stream);

    return 0;
}
user3553031
  • 5,990
  • 1
  • 20
  • 40
0

POSIX 2008 (e.g. most Linux systems) has getline(3) which heap-allocates a buffer for a line.

So you could code

 FILE* fil = fopen("something.txt","r");
 if (!fil) { perror("fopen"); exit(EXIT_FAILURE); };
 char *linebuf=NULL;
 size_t linesiz=0;
 if (getline(&linebuf, &linesiz, fil) {
   do_something_with(linebuf);
 }
 else { perror("getline"; exit(EXIT_FAILURE); }

If you want to read an editable line from stdin in a terminal consider GNU readline.

If you are restricted to pure C99 code you have to do the heap allocation yourself (malloc or calloc or perhaps -with care- realloc)

If you just want to copy the first line of some existing buffer char*bigbuf; which is non-NULL, valid, and zero-byte terminated:

char*line = NULL;
char *eol = strchr(bigbuf, '\n');
if (!eol) { // bigbuf is a single line so duplicate it
  line = strdup(bigbuf);
  if (!line) { perror("strdup"); exit(EXIT_FAILURE); }
} else {
    size_t linesize = eol-bugbuf;
    line = malloc(linesize+1);
    if (!line) { perror("malloc"); exit(EXIT_FAILURE);
    memcpy (line, bigbuf, linesize);
    line[linesize] = '\0';
}
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547