Related
I'm trying to read the following type of input
2
string1
string2
where the first line indicates the amount of strings following below, and the strings are all of (some) same length. Next, I'd like to print these strings in my program, which I was thinking of doing as follows.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main()
{
int n;
scanf("%d", &n);
char* s;
scanf("%s", s);
int l = strlen(s);
char input[n][l];
strcpy(s, input[0]);
for (int i = 1; i < n; i++) {
scanf("%s", s);
strcpy(s, input[i]);
}
print_string_array(input, n);
}
But I get the following warnings and error.
main.c: In function ‘main’:
main.c:24:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
24 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(l)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(l)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Why isn't my array input recognized as a char** type? And how would I go about fixing this without removing the general properties of my current program (for example, adaptability to any length of input strings)?
EDIT:
I've corrected some mistakes from not having coded in C for years (which may be a war crime from what I've seen in the comments):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(input, n);
for (int i=0; i<n; i++){
free(input[i]);
}
free(input);
}
But I still get some errors and warnings which I would like to solve.
main.c: In function ‘main’:
main.c:22:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
22 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(n)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Starting with the warnings, obviously I change the type of a from char** to something else. However, should I really give it the type char (*)[(sizetype)(n)]?? Also, there's the problem of segmentaion fault which is happening somewhere in the for loop.
Besides the problems in your code that are explained in the comments.
input is a char* that points to an array in memory that is of size n*l and not a char**, which is a pointer to a char*.
You would need to allocate an array of char*[] and then add each char* pointer that you get from scanf to that array.
The Variable Length Array input[n][l+1] does not need to be free'd.
The input[n][l+1] array is not a pointer to pointer **a. There are differences in the memory arrangement and they are not compatible.
void print_string_array( int size, int len, char (*a)[len]){ gives the compiler the dimensions of the VLA so the function can access it correctly.
scanf("%99s", s); will limit the input to no more than 99 characters. There is a problem in limiting input in scanf("%s", input[i]); to avoid putting too many characters into input[i].
#include <stdio.h>
#include <string.h>
void print_string_array( int size, int len, char (*a)[len]){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%99s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(n, l + 1, input);
}
Maybe this will help you out. It shows an example of dynamic string allocation
char buffer[101];
printf("Enter your name: ");
// Stores the name into auxiliary memory
scanf(" %100[^\n]", buffer);
// Creates a dynamic string
char* name = (char *) malloc(strlen(buffer) + 1);
//or use char* name = strdup(buffer) as pointed out by #Cheatah in the comments
// Sets the value
strcpy(name, buffer);
printf("Your name is %s", name);
// Frees the memory
free(name);
If you are just to print the strings one after the other, as you receive them, there's no need to store the full set of strings (or even a complete string) to do the task, you can implement a simple (4 states) automaton to read the number of strings, then print the strings as you are receiving their characters (character by character). This allows you to handle any length strings (like hundreds of megabyte strings) and upto 4,294,967,295 strings. (more if I change the declaration of n) and you'll get a far more efficient program that starts printing as soon as possible, instead of reading everything before printing anything.
#include <stdio.h>
#include <stdlib.h>
#define IN_STRING (0)
#define AFTER_NUMBER (1)
#define IN_NUMBER (2)
#define PRE_NUMBER (3)
#define F(_fmt) "%s:%d:%s:"_fmt, __FILE__, __LINE__, __func__
#define ERR_TAIL(E_fmt, ...) do { \
fprintf(stderr, _fmt, ##__VA_ARGS__); \
exit(1); \
} while(0)
#define ERR(ERR_fmt, ...) \
ERR_TAIL(F("ERROR: "_fmt), ##__VA_ARGS__)
int main()
{
int c, /* to hold the char */
last_char = EOF, /* to hold the prvious char */
status = PRE_NUMBER; /* state of the automaton */
unsigned n = 0; /* number of strings to read */
while ((c = fgetc(stdin)) != EOF) {
switch (status) {
case PRE_NUMBER:
switch(c) {
case ' ': case '\n': case '\t':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
status = IN_NUMBER;
n = c - '0';
break;
default: /* error */
ERR("Sintax error on input: non"
" digit character '%c' before "
"first number\n", c);
return 1;
} /* switch */
break;
case IN_NUMBER:
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n *= 10;
n += c - '0';
break;
case '\n':
status = IN_STRING;
break;
default:
status = AFTER_NUMBER;
break;
} /* switch */
break;
case AFTER_NUMBER:
switch (c) {
case '\n':
status = IN_STRING;
break;
case '\t': case ' ': /* ignored */
break;
default: /* error */
ERR("Sintax error on input: extra"
" character '%c' after first "
"number\n", c);
exit(1);
} /* switch */
break;
case IN_STRING:
switch (c) {
case '\n':
fputc(c, stdout);
if (!--n)
exit(0);
break;
default:
fputc(c, stdout);
break;
} /* switch */
break;
} /* switch */
last_char = c;
} /* while */
int exit_code = 0;
/* decide what to do when we receive a premature EOF */
switch(status) {
case PRE_NUMBER: /* before reading a number */
ERR("No number read before the strings\n");
exit_code = 1;
break;
case IN_NUMBER: /* in a number or in the spaces */
case AFTER_NUMBER: /* after the first newline */
fprintf(stderr,
"Nothing read after the number of strings\n");
exit_code = 1;
break;
case IN_STRING: /* IN_STRING, but */
if (last_char != '\n')
fputc('\n', stdout);
} /* switch */
return exit_code;
} /* main */
anyway, in your code:
char* s;
scanf("%s", s);
you cannot pass scanf() a pointer value that has not been initialized with enough memory to hold the string to be read.
On other side, beware that variable array declaracions (VAD) are controversial, as many compilers don't implement them and your code will not be portable, when you declare an array as VAD, you reserve space in the stack for the array, this being probably a mess if you end declaring very big arrays. The best and most portable way of declaring an array is to declare it with a constant expression (an expression that doesn't change at run time / an expression that is calculated by the compiler at compilation time) This is not your case, as you want to hold as big lines and as many as you like, with the only restriction that all the strings must have the same length as the first one (which you cannot enforce in any way)
One reason for the VADs being controversial is related to the following warning you have in your code
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
This informs you that a char ** is not the same type as a pointer to an array of n elements, on pointer decayment when passing it as parameter (the decayment happens only to the outer pointer, not to the inner ones). Decayment goes to the first level only, as the second/third/etc. are pointers to arrays, and so, the referred elements are not pointers, but arrays of n elements. When you increment a pointer char * or you do pointer arithmetic, you increment the address stored in that pointer variable by one because the pointed to type is an array. But when you increment a pointer char (*)[10] (a pointer to a ten element char array) you increment the address stored in that pointer by 10, so you cannot use pointer arithmetic, as you have declared it as a double pointer and it will be increased by sizeof (char *) (which is not what you want, 8 bytes, the size of a pointer)
Almost all the things commented lead you to Undefined Behaviour, and it is normal that you are getting that error. If I hade to write your code (and conserve the strings before doing anything) I would use dynamic memory with malloc(3) and realloc(3) as I parse the input.
Please look the code below
#include<stdio.h>
char* day(int);
int main()
{
int num;
char *p;
printf("Enter the day \n");
scanf("%d",&num);
p=day(num);
printf("%s",*p);
return 0;
}
char *day(int num)
{
char *str;
switch(num)
{
case 1: *str="MONDAY";
break;
case 2: *str="TUESDAY";
break;
case 3: *str="WEDNESDAY";
break;
case 4: *str="THURSDAY";
break;
case 5: *str="FRIDAY";
break;
case 6: *str="SATURDAY";
break;
case 7: *str="SUNDAY";
break;
}
return str;
}
I'm trying to print the days in a week in the above program in order to achieve this I have created a function day() which will accept the number from the user and will return the address of day but the above program is not working .I don't know what is the problem.Can anyone help me to solve this problem?
Remove '*' from str in day function, as you are assigning contents through pointers
Go through Basic Pointer Operations for pointer fundamentals.
#include<stdio.h>
char* day(int);
int main()
{
int num;
char *p;
printf("Enter the day \n");
scanf("%d",&num);
p=day(5);
printf("%s",p);
return 0;
}
char* day(int num)
{
char* str;
switch(num)
{
case 1: str="MONDAY";
break;
case 2: str="TUESDAY";
break;
case 3: str="WEDNESDAY";
break;
case 4: str="THURSDAY";
break;
case 5: str="FRIDAY";
break;
case 6: str="SATURDAY";
break;
case 7: str="SUNDAY";
break;
}
return str;
}
I hope it does make sense to you....
You want to use printf("%s" p) without the '*'.
*p means the value at the address that is stored in p. p is a char pointer, so if you used that, you would only be passing a single char to printf.
If you don't use the '*' you are passing the address in memory that to string starts at. This lets printf print that first char, then the second, then third and so on until it reaches the end of the string (a null character, '\0').
Also, when you are assigning the string to the char pointer, you don't want to use '*' there either. See Maharajs answer for working code.
I have strings like "− · · · −" (Morse code) in an array, and want to tokenize each string to get each individual dot(.) and dash(−). A part of my code is given below:
char *code, *token;
char x;
char ch[4096];
code = &ch[0];
..
while((x = tolower(fgetc(fp))) != EOF){
printf("%c \n", x);
switch(x){
case 'a':
strcpy(code, "· −");
break;
case 'b':
strcpy(code, "− · · ·");
break;
case 'c':
strcpy(code, "− · − · ");
break;
case 'd':
strcpy(code, "− · ·");
break;
case 'e':
strcpy(code, "· ");
break;
case 'f':
strcpy(code, "· · − ·" );
break;
case 'g':
strcpy(code, "− − · ");
break;
case 'h':
}
if(x!= 10){
printf("Value read : %s \n", code);
token = strtok(code, " ");
while(token != NULL){
printf("CHARACTER: %s\n", token);
token = strtok(NULL, " ");
}
}
So, when the code array has "− − ·", I want the output to have:
CHARACTER: −
CHARACTER: −
CHARACTER: ·
However, the output is instead having CHARACTER: − − ·
I am new to string tokenizing, and might made a mistake somewhere there. Perhaps my delimiter is wrong, I am not sure. I hope I have provided enough information. Any help on this would be greatly appreciated.
Thanks in advance
The issue is that the (Unicode) whitespace character in the string literals (e.g. "· · − ·") is different to the whitespace character in the strtok() calls.
Run your source code through xxd and see for yourself.
As far as I can see, the spaces in the strcpy() calls are U+200A whereas the spaces in the strtok() calls are U+0020.
Strtok is not needed thing here (and you don't need those spaces either). If you want the individual characters from the string you could use a simple loop with a pointer over the original string:
char *current=&code;
Then make sure you loop until the end of string (null) character:
while (*current != 0x0) {
if(*current != ' ') {
printf("CHARACTER: %c \n", *current);
current ++;
}
}
What this does:
loops over the characters in code, using current as a pointer, and checking for the null terminator.
It then uses an if to check for a space, and if the character is not a space, format prints it - derefing the pointer to the char there.
Finally it increments the pointer.
Big warning: If you string is not zero terminated (a standard C string will be), this will start printing silly stuff.
Me again with another segmentation fault(groan).
To get where i am now i have had help in other questions on here.
The idea behind this function is:
pass in a char*
duplicate the passed in char* onto the heap and point to this location
use strsep to split the "string" based on the ',' delimiter
assign these split tokens to struct variables
free the pointers
This is what i pass to the function:
gga_sentence struct:
typedef struct gga_sentence{
const char *untouched_sentence;
gsa_sentence *gsa;
char *sentence_id;
int time_stamp;
double latitude;
char north_south_id;
double longitude;
char east_west_id;
int quality;
int no_of_satellites;
double horizontal_dillution;
double altitude;
char altitude_units;
double geodial_seperation;
char geodial_seperation_units;
char* age_of_data_in_seconds;
char *checksum;
}gga_sentence;
gga_parsed is:
gga_sentence *ggas_parsed;
ggas_parsed = malloc(10*sizeof(gga_sentence));
where line is a char[100] which is filled using a line read from a file, this works fine.
strncpy(&ggas_parsed[number_of_gga_parsed].untouched_sentence, line, strlen(line));
printf("GGA UNTOUCHED: %s", &ggas_parsed[number_of_gga_parsed].untouched_sentence);
initiate_gga_values(&ggas_parsed[number_of_gga_parsed], &ggas_parsed[number_of_gga_parsed].untouched_sentence);
The above printf statement:
printf("GGA UNTOUCHED: %s", &ggas_parsed[number_of_gga_parsed].untouched_sentence);
produces:
GGA UNTOUCHED: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
so when i pass this to the function as described above by:
initiate_gga_values(&ggas_parsed[number_of_gga_parsed], &ggas_parsed[number_of_gga_parsed].untouched_sentence);
where the function itsef is defined as:
void initiate_gga_values(gga_sentence* gga_ptr, const char* sentence){
char *temp_sentence, *second_temp_ptr;
char *token;
int token_no = 0;
temp_sentence = strdup(sentence);
second_temp_ptr = temp_sentence;
printf("TS: %s", temp_sentence);
printf("2nd: %s", second_temp_ptr);
token = strsep (&second_temp_ptr,",");
while (token != NULL) {
/*if a sentence has missing data then make that clear by settings it's value to
* <EMPTY>*/
if(strlen(token)==0){
token = "<EMPTY>";
}
switch(token_no){
case 0:
gga_ptr->sentence_id = token;
//printf("%s,",gga_ptr->sentence_id);
break;
case 1:
/*atoi converts a string to an int, well a c string anyways so a char* */
gga_ptr->time_stamp = atoi(token);
//printf("%d,",gga_ptr->time_stamp);
break;
case 2:
/*strtod coverts a string to a double, well a c string anyways so a char* */
gga_ptr->latitude = strtod(token, NULL);
//printf("%f,",gga_ptr->latitude);
break;
case 3:
gga_ptr->north_south_id = *token;
//printf("%c,",gga_ptr->north_south_id);
break;
case 4:
gga_ptr->longitude = strtod(token, NULL);
//printf("%f,",gga_ptr->longitude);
break;
case 5:
gga_ptr->east_west_id = *token;
//printf("%c,",gga_ptr->east_west_id);
break;
case 6:
gga_ptr->quality = atoi(token);
//printf("%d,",gga_ptr->quality);
break;
case 7:
gga_ptr->no_of_satellites = atoi(token);
//printf("%d,",gga_ptr->no_of_satellites);
break;
case 8:
gga_ptr->horizontal_dillution = strtod(token, NULL);
//printf("%f,",gga_ptr->horizontal_dillution);
break;
case 9:
gga_ptr->altitude = strtod(token, NULL);
//printf("%f,",gga_ptr->altitude);
break;
case 10:
gga_ptr->altitude_units = *token;
//printf("%c,",gga_ptr->altitude_units);
break;
case 11:
gga_ptr->geodial_seperation = strtod(token, NULL);
//printf("%f,",gga_ptr->geodial_seperation);
break;
case 12:
gga_ptr->geodial_seperation_units = *token;
//printf("%c,",gga_ptr->geodial_seperation_units);
break;
case 13:
/*This is never used in the sentenced given*/
gga_ptr->age_of_data_in_seconds = token;
//printf("%s,",gga_ptr->age_of_data_in_seconds);
break;
case 14:
gga_ptr->checksum = token;
//printf("%s",gga_ptr->checksum);
break;
}
token_no++;
token = strsep (&second_temp_ptr, ",");
}
printf("untouched: %s\n", sentence);
printf("Second print of TS: %s\n", temp_sentence);
printf("second print of second_temp: %s\n", second_temp_ptr);
free(temp_sentence);
exit(1); //DBUGGING PURPOSES
}
The output from this function is:
TS: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
2nd: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
untouched: $GPGGA,151019.00�(m
Second print of TS: $GPGGA
second print of second_temp: (null)
so if i add this printf statement:
printf("testing untouched: %s", gga_ptr->untouched_sentence);
into the initiate_gga_values function, just before the exit(1) i get a segmentation fault. The output of running the code again with the extra print line which prints a gga_ptr->untouched_sentence produces:
GGA UNTOUCHED: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
TS: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
2nd: $GPGGA,151019.000,5225.9627,N,00401.1624,W,1,09,1.0,38.9,M,51.1,M,,0000*72
untouched: $GPGGA,151019.00��b
Second print of TS: $GPGGA
second print of second_temp: (null)
Segmentation fault (core dumped)
I have no idea what is going on.
Any ideas?
Cheers,
Chris.
This is wrong:
const char* untouched_sentence;
strncpy(&ggas_parsed[number_of_gga_parsed].untouched_sentence, line, strlen(line));
printf("GGA UNTOUCHED: %s", &ggas_parsed[number_of_gga_parsed].untouched_sentence);
The first argument to strncpy should be a buffer to put the copy into, you've given it a pointer into your structure. The third argument should be the size of the destination buffer, not the input!
You need to do:
char* untouched_sentence;
ggas_parsed[number_of_gga_parsed].untouched_sentence = malloc(<size>);
Where <size> needs to be strlen(line) with some restriction if you are worried about long lines.
Then:
strncpy(ggas_parsed[number_of_gga_parsed].untouched_sentence, line, strlen(line));
printf("GGA UNTOUCHED: %s",ggas_parsed[number_of_gga_parsed].untouched_sentence);
I think you need to start with a simpler example to get your head around memory management.
I am reversing the string so for example if I input word 'try' it would read y as a vowel and print out the word is legal.
The reverse function works but it doesn't pass to the switch statement value.
#include
//#include
void rev(char *);
void legal(char string);
int main()
{
char string[50];
char temp;
printf("Enter any string:");
scanf(" %s",&string);
//printf("Before reversing the string %s\t",string);
rev(string);
printf("\nReverse String is %s",string);
temp = legal(string);
printf("\nReverse String is %s",temp);
return 0;
}
void legal(char string)
{
switch(string)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'Y':
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
printf("\nWord is legal");
break;
default:
printf("\nWord is not legal");
break;
}
return 0;
}
//reversing string using pointers
void rev(char *str)
{
char *str1,temp;
str1=str;
while(*str1!='\0')
str1++;
str1--;
while(str<str1)
{
temp=*str;
*str=*str1;
*str1=temp;
str++;
str1--;
}
}
I see you have mistaken a char * with a char.
Instead, you must loop through the string, character by character and figure out with a flag if the word is legal or not..
here is how I would do it, not tested code ahead:
void rev(char *);
void legal(char *string);
int main()
{
char string[50];
int temp;
printf("Enter any string:");
scanf(" %s",&string);
//printf("Before reversing the string %s\t",string);
rev(string);
printf("\nReverse String is %s",string);
temp = legal(string);
printf("\nLegal? %d",temp);
return 0;
}
int legal(char *string)
{
char *ch = string;
int flag = 0;
while(*ch != '\0'){
switch(*ch)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'Y':
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
flag = 1;
break;
default:
//nothing
break;
}
}
if(flag == 1){
printf("word is legal!");
}else{
printf("word is illegal!");
}
return flag;
}
C++ doesn't allow string or arrays in switch instructions, that might be the problem.
Plus you're assigning tempt to 0.
There are several errors in your code.
void legal(char string); returns a void, but you attempt to assign it here:
temp = legal(string);
legal takes a char, but you try to pass a char [] to it.
You return 0; in legal.
The problem is that the variable string is an array, while legal only accepts single char values. You can fix this by accepting a pointer or an array or some combination there-of and only checking the first digit if that is what you want.
Your corrected code would look like this:
void legal(char *string);
and then inside the legal function, you can reference the first character as *string.