how can I parse a string like this (6,8) - c

I want to parse a string in a format as (6,8), and I want to store 6 and 8 in different variable. I'm trying to use the "strtok". However it gives me a segfault
here is my code
int main()
{
char a[80]="(6,8)";
parsing(a);
return 0;
}
int parsing(char* a)
{
char* word;
char temp[80] ;
stpcpy(temp,a);
char* new;
char **newendptr=NULL;
char **newnewendptr=NULL;
int u,v;
word= strtok(temp, "(");
word= strtok(NULL, ",");
u=strtoumax(secword,newendptr,0);
printf("%d\n",u);
new= strtok(NULL, ")");
printf("%s\n",new);
v=strtoumax(new,newnewendptr,0);
printf("%d %d",u,v);
return 1;
}

It pays to read the specification of strtok() carefully.
This code works:
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
static int parsing(char *a)
{
char temp[80];
strcpy(temp, a);
printf("temp 0 = %p [[%s]]\n", (void *)temp, temp);
char *word1 = strtok(temp, "(,)");
printf("word 1 = %p [[%s]]\n", (void *)word1, word1 == 0 ? "<nothing>" : word1);
char *word2 = strtok(NULL, "(,)");
printf("word 2 = %p [[%s]]\n", (void *)word2, word2 == 0 ? "<nothing>" : word2);
int u = strtoumax(word1, 0, 0);
int v = strtoumax(word2, 0, 0);
printf("%d %d\n", u, v);
return 1;
}
int main(void)
{
char a[80] = "(6,8)";
parsing(a);
return 0;
}
The output on my machine is:
temp 0 = 0x7fff54844440 [[(6,8)]]
word 1 = 0x7fff54844441 [[6]]
word 2 = 0x7fff54844443 [[8]]
6 8
The problem is that the call to strtok() in the original with "(" as delimiter skips over the opening (, but then doesn't find another to mark the end of the token, so the rest of the string is consumed. The second call to strtok() therefore has nothing to process and returns NULL.
The fixed code avoids that problem. The initial delimiter must include ( to skip that, and must include , to stop there. The second delimiter should include ); the other characters are not strictly needed.
Since you aren't inspecting the output pointer that's the second argument to strtoumax(), it may as well be NULL (aka 0) each time. Using strtoumax() and assigning the result to an int is a little odd. With the given data, it is OK, but more generally, it risks losing important information. The strtoX() functions are quite powerful but also remarkably delicate in how they report out of bounds values, etc. This usage throws away all that information (and you'd need to set errno to 0 before calling it, and you'd have to save the values in uintmax_t variables, to get and preserve the information accurately).
In this context, a more succinct (but not necessarily simpler) way to parse the input string would be:
char c;
if (sscanf(a, " (%d ,%d %c", &u, &v, &c) != 3 || c != ')')
…oops — malformatted data…
Make sure you know why the spaces are present and why they are where they are. That may require careful scrutiny of the POSIX specification for sscanf(). You can decide to do without the spaces; you need to know what the consequences of doing so are. If you want to be sure that the whole string was parsed, use:
char c;
int n;
if (sscanf(a, " (%d ,%d %c%n", &u, &v, &c, &n) != 3 || c != ')' || temp[n] != '\0')
…Oops…
Note that %n conversion specifications are not counted so the 3 does not change.

The answer given by #Jonathan Leffler seems to have covered what was not working in your original code nicely. I just thought that I would add a solution that will parse strings containing n-tuples of unknown length. Here, the parsing() function takes as arguments an address of a pointer to int, which is where a simulated array of numbers will be stored, and an input string, which should be formatted as "(int1, int2, ...)". I make no promises about the behavior of this function with malformed input. The function allocates space, stores the numbers in the simulated array, and returns the number of numbers found.
I included a function to display the parsed numbers, and even wrapped the call to realloc() in a function to catch allocation errors. I also added a few more examples to show how it responds to some different inputs. Of course, since my version of parsing() allocates memory, the caller is responsible for freeing it.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t parsing(int **nums, char *a);
void * xrealloc(void *ptr, size_t size);
void shownums(int *nums, size_t n);
int main(void)
{
int *nums = NULL;
size_t n;
char a[80] = "(6, 8)";
char b[80] = "(2, 3, 5)";
char c[80] = "(7)";
char d[80] = "(11,)";
char e[80] = "(2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 5)";
n = parsing(&nums, a);
shownums(nums, n);
n = parsing(&nums, b);
shownums(nums, n);
n = parsing(&nums, c);
shownums(nums, n);
n = parsing(&nums, d);
shownums(nums, n);
n = parsing(&nums, e);
shownums(nums, n);
/* Free allocated memory */
free(nums);
return 0;
}
size_t parsing(int **nums, char *a)
{
size_t nums_sz = 0;
char *res;
while ((res = strtok(a, "(,)"))) {
nums_sz++;
*nums = realloc(*nums, sizeof(int) * nums_sz);
(*nums)[nums_sz - 1] = atoi(res);
a = NULL;
}
return nums_sz;
}
void * xrealloc(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (ret == NULL) {
fprintf(stderr, "Unable to allocate memory\n");
exit(EXIT_FAILURE);
}
return ret;
}
void shownums(int *nums, size_t n)
{
for (size_t i = 0; i < n; i++)
printf("%d ", nums[i]);
putchar('\n');
}
And here is the output:
6 8
2 3 5
7
11
2 7 1 8 2 8 1 8 2 8 5

Related

I got segmentation fault (core dumped) when i use realloc at dynamic array input functions

i wrote a combination output code for an input array. i wrote an input_array function for an new array. i wrote an input_decimal_number function for an size_t type single-number. i set N as the number of elements in a combination. And i pass compilation. Here is code followed:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
size_t input_decimal_number(void);
size_t input_array(int *array);
void combination(const int *array, int *combination_array,
size_t start, const size_t end, const size_t N, size_t i);
int main(void)
{
size_t N, LEN;
int *array;
array = (int *)malloc(sizeof(int));
LEN = input_array(array);
printf("enter N value(0 < N <= %zd):\n", LEN); /* N is number of elements in a combination */
while ((N = input_decimal_number()) > LEN)
printf("N > %zd, enter N again: ", LEN);
int combination_array[N];
puts("Here are all combinations for this integer array:");
combination(array, combination_array, 0, LEN - 1, N, 0);
return 0;
}
size_t input_decimal_number(void)
{ /* here is a common size_t type single-number input functions */
size_t decimal_number;
_Bool input_check;
while ((input_check = fscanf(stdin, "%zd", &decimal_number)) != 1)
if (input_check != 1)
{
scanf("%*s");
fprintf(stdout, "invalid input, enter this number again: ");
}
return decimal_number;
}
size_t input_array(int *array)
{ /* this is input array functions */
size_t LEN = 0;
char buf[BUFSIZ];
void *alloc_check;
fprintf(stdout, "Enter decimal integer arrays(use spaces key to separate every number):\n");
while (fscanf(stdin, "%d", &array[LEN]) == 1)
{
alloc_check = realloc(array, (LEN + 1) * sizeof(int));
if (alloc_check == NULL)
;
else
array = (int *)alloc_check;
/* dynamically allocate memory for array */
LEN++;
if (getchar() == '\n')
break;
}
if (LEN == 0)
{
printf("no number entered correctly.\n");
exit(EXIT_FAILURE);
} /*if no input, exit the whole program */
setbuf(stdin, NULL);
setvbuf(stdin, buf, _IOLBF, BUFSIZ);
/* skip rest of input content */
return LEN;
}
void combination(const int *array, int *combination_array,
size_t start, const size_t end, const size_t N, size_t i)
{
/* this functions could find all combination of N elements in an array*/
if (i == N)
{
for (int k = 0; k < N; k++)
printf("%d ", combination_array[k]);
putchar('\n');
return;
}
for (start; start <= end && end - start + 1 >= N - i; start++)
/* "end-start+1 >= N-i" makes sure that including i at N will make a combination with remaining elements at remaining positions */
{
combination_array[i] = array[start];
combination(array, combination_array, start + 1, end, N, i + 1);
}
}
when i input such like 1 2 3 4 5 6, and input N again it turned to be ok! But if i input 1 2 3 4 5 6 7, it turned to be realloc(): invalid next size Aborted (core dumped), why?
You have a corrupted heap, which leads to undefined behavior, think about what happens in the second iteration of while (fscanf(stdin, "%d", &array[LEN]) == 1), when it's called to grab the second input, the allocated memory still only has space for one int but you assign the value to array[1] which means the array should have at least space for 2 ints, but the second is not allocated yet.
Quick fix, use (LEN + 2).
To pass the allocated space to caller function, in this case the main function:
You would need to pass it by pointer to pointer (aka double pointer) argument.
Or to return the pointer to the allocated space, and then return LEN by other means, for instance, by a pointer argument.
For the latter:
int *input_array(size_t *LEN) {//LEN will be passed as an argument pointer
int *array;
if ((array = malloc(sizeof *array)) == NULL) { //same as sizeof(int) but safer
perror("malloc");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Enter decimal integer arrays(space to separate every number):\n");
while (fscanf(stdin, "%d", &array[*LEN]) == 1) {
//no need for auxiliary pointer
if ((array = realloc(array, (*LEN + 2) * sizeof *array)) == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
(*LEN)++;
if (getchar() == '\n')
break;
}
if (LEN == 0) {
fprintf(stderr, "no number entered correctly.\n");
exit(EXIT_FAILURE);
}
return array; //return the allocated space
}
And in main:
//...
size_t N, LEN = 0;
int *array;
array = input_array(&LEN); //allocated space assigned to array and LEN as an argument pointer
//...
Live demo
There are still potencial issues in the combination function, as N grows the number of combinations shrinks to the point that if N == LEN, the only printed combination is the array itself, if that is not the expected output you should also address that.
size_t format specifier is %zu.
Use size_t i = 0 in the for loop for signedness comparation consistency.
Your input_array() function has another issue: you are setting the buffer for stdin to a local array that ceases to exist when the function returns:
size_t input_array(int *array)
{ /* this is input array functions */
size_t LEN = 0;
char buf[BUFSIZ]; <===== This array ceases to exist when this function returns
...
setbuf(stdin, NULL);
setvbuf(stdin, buf, _IOLBF, BUFSIZ); <==== stdin's buffer will disappear
/* skip rest of input content */
return LEN;
}
Since you're only calling input_array() once, the easiest fix is to make buf static so it exists as long as the program is running:
static char buf[BUFSIZ];
Without static each time input_array() is called, each call of the function will have its own buf array. If two threads are running at the same time, there will be two buf arrays in your program. But those arrays will cease to exist when the function returns.
With the addition of the static keyword, there will only be one buf array, it will exist as long as the program is running, and it will be shared by all invocations of input_array().

snprintf usage for making up formatted strings

I'm trying to learn about the snprintf and found this answer with the example:
char buf[20] = "";
char *cur = buf, * const end = buf + sizeof buf;
cur += snprintf(cur, end-cur, "%s", "foo");
printf("%s\n", buf);
if (cur < end) {
cur += snprintf(cur, end-cur, "%s", " bar");
}
printf("%s\n", buf);
free(str);
The thing that is not clear to me is that we allocate a fixed hardcoded buffer size which seems suffer from buffer overflow. In the N1570 I found that (7.21.6.5)
1
#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);
2 The snprintf function is equivalent to fprintf, except that the
output is written into an array (specified by argument s) rather than
to a stream. If n is zero, nothing is written, and s may be a null
pointer.
So to me it appears as the idiomatic usage would be as follows:
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1; //How much to allocate?
char *const str = malloc(need_space * sizeof(char)); //allocate
int written = snprintf(str, need_space, "abs %s", "fgh"); //do format
printf("Need space = %d, written = %d\n", need_space, written);
printf("%s\n", str);
Or this is not common and has another problem?
The 2x call to snprintf() is a common idiom.
... has another problem?
Problems lie in the corners
Format maintenance
The below suffers from a repeated format - prone to breaking as code ages and and only one line is changed.
// Oops!
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1;
char *const str = malloc(need_space * sizeof(char));
int written = snprintf(str, need_space, "abs %s ", "fgh");
Did you notice the difference?
Better to state the format once.
#define FMT_ABS_S "abs %s"
int need_space = snprintf(NULL, 0, FMT_ABS_S, "fgh");
char *const str = malloc(sizeof *str * (need_space + 1u));
int written = snprintf(str, need_space, FMT_ABS_S, "fgh");
Volatility
Code needs to insure the values do not change (non-volatile) between the 2 calls and special concern arise in multi-threaded applications.
Error checking
Code lacked checks. Yet even with checks, how to even handle unexpected results - perhaps just bail?
static const char *fmt_s = "abs %s";
int needed_space = snprintf(NULL, 0, fmt_s, "fgh");
if (needed_space < 0) {
Handle_EncodingError();
}
char * const str = malloc(sizeof *str * (needed_space + 1u));
if (str == NULL) {
Handle_OutOfMemory();
}
int written = snprintf(str, needed_space, fmt_s, "fgh");
if (written < 0 || written > needed_space) {
Handle_Error();
}
Going twice though
2 calls can be wasteful in select situations, yet commonly the impact is less than thought. #Jonathan Leffler
Yet for me, the "what to do if allocation fails" is a show stopper anyways and code reports the error and maybe exit.
Selectively, once is enough
When the s*printf() format is tightly controlled, I see 1 call as sufficient.
// int to string
#define LOG2_N 28
#define LOG2_D 93
// Number of char needed for a string of INT_MIN is log10(bit width) + 3
#define INT_SIZE ((sizeof(int)*CHAR_BIT-1)*LOG2_N/LOG2_D + 3)
char s[INT_SIZE * 2]; // I like to use 2x to handle locale issues, no need to be stingy here.
int len = snprintf(s, sizeof s, "%d", i);
if (len < 0 || (unsigned) len >= sizeof s) {
Handle_VeryUnusualFailure();
}

Create variable numbers of string variables according to users's input(C language)

I would like to create an array of string variables, and the number of elements is depends on the user's input. For example, if the user's input is 3, then he can input 3 strings. Let's say "aaa", "bbb" and "ccc". They are stored by the same pointer to char(*ptr) but with different index.
code:
int main()
{
int t;
scanf("%d", &t);
getchar();
char *ptr = malloc(t*sizeof(char));
int i;
for(i=0;i<t;i++)
{
gets(*(ptr[i]));
}
for(i=0;i<t;i++)
{
puts(*(ptr[i]));
}
return 0;
}
t is the number of elements, *ptr is the pointer to array. I would like to store "aaa", "bbb" and "ccc" in ptr[0], ptr[1] and ptr[2]. However, errors have been found in gets and puts statement and i am not able to work out a solution. Would someone give a help to me? Thank you!
You shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and deleted from C11.
Only one character can be stored in char. If the maximum length of strings to be inputted is fixed, you can allocate an array whose elements are arrays of char. Otherwise, you should use an array of char*.
Try this (this is for former case):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* the maximum length of strings to be read */
#define STRING_MAX 8
int main(void)
{
int t;
if (scanf("%d", &t) != 1)
{
fputs("read t error\n", stderr);
return 1;
}
getchar();
/* +2 for newline and terminating null-character */
char (*ptr)[STRING_MAX + 2] = malloc(t*sizeof(char[STRING_MAX + 2]));
if (ptr == NULL)
{
perror("malloc");
return 1;
}
int i;
for(i=0;i<t;i++)
{
if (fgets(ptr[i], sizeof(ptr[i]), stdin) == NULL)
{
fprintf(stderr, "read ptr[%d] error\n", i);
return 1;
}
/* remove newline character */
char *lf;
if ((lf = strchr(ptr[i], '\n')) != NULL) *lf = '\0';
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
free(ptr);
return 0;
}
You can use this code which is given below because string array is like char 2D array so use can use pointer of pointer and when you allocate memory at run time by malloc then you need to cast into pointer to pointer char type.
int main()
{
int t;
scanf("%d", &t);
char **ptr = (char **)malloc(t*sizeof(char));
int i,j;
for( i=0;i<t;i++)
{
scanf("%s",ptr[i]);
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
return 0;
}
Here is an example, of a clean if slightly memory inefficient way to handle this. A more memory efficient solution would use one string of MAX_LINE_LENGTH and copy to strings of precise lengths.. which is why one contiguous block of memory for the strings is a bad idea.
The asserts also just demonstrate where real checks are needed as malloc is allowed to fail in production where asserts do nothing.
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define MAX_LINE_LENGTH 2048
int
main(void) {
int tot, i;
char **strheads; /* A pointer to the start of the char pointers */
if (scanf("%d\n", &tot) < 1)
return (1);
strheads = malloc(tot * sizeof (char *));
assert(strheads != NULL);
/* now we have our series of n pointers to chars,
but nowhere allocated to put the char strings themselves. */
for (i = 0; i < tot; i++) {
strheads[i] = malloc(sizeof (char *) * MAX_LINE_LENGTH);
assert(strheads[i] != NULL);
/* now we have a place to put the i'th string,
pointed to by pointer strheads[i] */
(void) fgets(strheads[i], MAX_LINE_LENGTH, stdin);
}
(void) printf("back at ya:\n");
for (i = 0; i < tot; i++) {
fputs(strheads[i], stdout);
free(strheads[i]); /* goodbye, i'th string */
}
free(strheads); /* goodbye, char pointers [0...tot] */
return (0);
}

How do I convert a string to a numeric value in C?

It would be better If I show you guys an example of what my program is supposed to do.
Input:
3
Double Double End
Triple Double End
Quadruple Double Triple End
Output:
4
6
24
So, the first sentence Double Double means 2*2 and Triple Double means 3*2 and so on.
The word End signifies the end of the string.
It looks very simple, but I have no idea how to work with strings and give them a value and continue on from there.
Here is all I have done so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num_of_orders,i,j;
char orders[25];
char str1[25] = "Double";
char str2[25] = "Triple";
char str3[25] = "Quadruple";
scanf("%d", &num_of_orders);
for (i=0; i<num_of_orders+1; i++){
scanf("%s", orders);
}
return 0;
}
There are a number of ways to approach this problem, as indicated by the variety of answers. There is often no one right answer for how to approach a problem in C. The standard library provides a variety of tools that allow you to craft a number of solutions to just about any problem. As long as the code is correct and protects against error, then the choice of which approach to take largely boils down to a question of efficiency. For small bits of example code, that is rarely a consideration.
One approach to take is to recognize that you do not need the first line in your data file (except to read it/discard it to move the file-position-indicator to the start of the first line containing data.)
This allows you to simply use a line-oriented input function (fgets or getline) to read the remaining lines in the file. strtok then provides a simple way to split each line into words (remembering to strip the '\n' or discard the last word in each line). Then it is a small matter of using strcmp to compare each word and multiply by the correct amount. Finally, output the product of the multiplication.
Here is one slightly different approach to the problem. The program will read from the filename given as the first argument (or from stdin by default):
#include <stdio.h>
#include <string.h>
enum { MAXC = 64 };
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* line buffer */
char *delims = " \n"; /* delimiters */
int idx = 0; /* line index */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file pointer */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line */
if (!idx++) continue; /* discard line 1 */
char *p = buf;
size_t len = strlen (p); /* get length */
int prod = 1;
if (len && buf[len-1] == '\n') /* check for '\n' */
buf[--len] = 0; /* remove newline */
printf (" %s", buf); /* output buf before strtok */
/* tokenize line/separate on delims */
for (p = strtok (p, delims); p; p = strtok (NULL, delims))
{ /* make comparson and multiply product */
if (strcmp (p, "Double") == 0) prod *= 2;
if (strcmp (p, "Triple") == 0) prod *= 3;
if (strcmp (p, "Quadruple") == 0) prod *= 4;
}
printf (" = %d\n", prod); /* output product */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Use/Output
$ ./bin/dbltrpl <../dat/dbltrpl.txt
Double Double End = 4
Triple Double End = 6
Quadruple Double Triple End = 24
Look it over and let me know if you have questions.
When it comes to reading the input, you can use strtok with a " " as a parameter to delimite the words you're reading from the input. This is a function filling all of the words read on the input into an array of strings:
PARAMETERS:
char **words: array of strings where you will store all of the words read in the input
char *input: the input you read (i.e. "Double Double end")
char *s: the delimiter you'll use to read words in the input (i.e. " ", "\n")
void getWords(char **words, char *input, char *s){
*words = strtok(str, s);
while(*words){
words++;
*words = strtok(NULL, s);
}
words++;
*words=NULL; //last element will point to NULL
}
Once you have read the words from the input, and filled them inside an array of strings, you could do something like this to calculate the output:
int calculate(char **words){
int result = 1;
while(*words){
if (strcmp(*words, "Quadruple") == 0){
result *= 4;
}else if (strcmp(*words, "Triple") == 0){
result *= 3;
}else if (strcmp(*words, "Double") == 0){
result *= 2;
}else if (strcmp(*words, "End") == 0){
return result;
}
words++;
}
}
Note that you need to correctly initialize the parameters you're passing before calling those functions. Otherwise, it may cause a Segmentation Fault.
You will have to use the methods from the string.h library, such as: strcmp(to compare two strings), strcpy(to copy one string to another) etc. which are generally used when dealing with strings manipulation in c.
Since, we do not know the size of the results array at compile time, we will have to allocate memory to it dynamically. For this purpose I have used malloc and free.
Here is the code to do that:
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
int num_of_orders, i, j;
char orders[25];
char str1[25];
strcpy(str1,"Double");
char str2[25];
strcpy(str2,"Triple");
char str3[25];
strcpy(str3,"Quadruple");
scanf("%d", &num_of_orders);
getchar();
int *results = malloc(num_of_orders*sizeof(int));
for (i=0; i < num_of_orders; i++)
{
results[i] = 1;
strcpy(orders,"");
while(strcmp(orders,"End") != 0)
{
scanf("%s", orders);
getchar();
if(strcmp(orders,str1)==0)
results[i] *= 2;
else if(strcmp(orders,str2) == 0)
results[i] *= 3;
else if(strcmp(orders,str3)==0)
results[i] *= 4;
}
}
for(i = 0; i < num_of_orders; i++)
printf("%d\n", results[i]);
free(results);
return 0;
}
Note: This program uses strcmp, which does case-sensitive comparison. If you want case-insensitive comparison, then use strcasecmp instead.
Don't forget the fact that the multiplication of integers is commutative:
#include <stdio.h>
#include <string.h>
int main(void)
{
int num_of_orders, i;
char orders[25];
int result;
char *ptr;
scanf("%d", &num_of_orders);
getchar(); // To comsume '\n'
for (i = 0; i < num_of_orders; i++)
{
fgets(orders, sizeof orders, stdin);
result = 1;
ptr = orders;
while(ptr = strstr(ptr, "Double"))
{
result *= 2;
ptr++;
}
ptr = orders;
while(ptr = strstr(ptr, "Triple"))
{
result *= 3;
ptr++;
}
ptr = orders;
while(ptr = strstr(ptr, "Quadruple"))
{
result *= 4;
ptr++;
}
printf("%d\n", result);
}
return 0;
}
What a trivial approach!
Note that strtok() is destructive, namely it will modify order, which can cause some problems if you want to use it later. Also, I think programs using strtok() are less readable. So it might be better to avoid it when possible.

C Beginner - Pointers

I'm having a little trouble understanding where my code goes wrong. I want to store into an array of strings multiple lines and after to display them; for some unknown reason after I enter a different number of lines ( let's say 5 ), it will only display the last line 5 times. Any idea?
Thank you
#include <stdio.h>
#include <string.h>
int readLine(char line[], int max);
void printLines(char *lines[], int size);
int main(){
char *lines[100];
char line[100];
int i = 0;
int len = 0;
char *p;
while( (len = readline(line,100)) > 0){
if((p = malloc(len * sizeof(char))) != NULL){
p = line;
lines[i++] = p;
}
}
lines[i] = '\0';
printLines(lines, i);
return 0;
}
int readline(char line[], int max){
if(fgets(line,max,stdin) == NULL)
return 0;
printf("%d \n", strlen(line));
return strlen(line);
}
void printLines(char *lines[], int size){
int i;
for(i = 0; i < size; i++)
printf("%s\n", lines[i]);
}
if((p = malloc(len * sizeof(char))) != NULL){
p = line;
lines[i++] = p;
You allocate memory for a string, and store the pointer returned from malloc() in p. Then you store a pointer to line in p, effectively throwing away the pointer to the memory you just allocated. You need to copy the string by using strcpy() or similar.
strcpy (p, line);
This is your problem:
if((p = malloc(len * sizeof(char))) != NULL){
p = line;
lines[i++] = p;
}
p is a pointer that points to allocated storage first, but then its value is overwritten with the value of line. What you want is to copy what is currently stored at the location that line points to to the location where p points to. The function for that is strcpy().
Notes:
sizeof (char) is by the very definition of sizeof exactly 1.
You will have buffer overflow issues (google that term!) if people enter lines longer than 100 chars.
You are not really handling malloc() failure but merely skipping some code and otherwise ignoring it. Write an error message and call exit() for now if malloc() fails. Wrap that in a function for easier reuse (ofter called xalloc()).

Resources