function getting stuck in a loop - c

I am doing a school project in C and I am stuck at this puzzle.
So, we need to implement a message passing system using sockets for 100 users.
I am storing my users' data in this struct.
typedef struct user
{
char username[20];
int online; //flag value 1 = online, 0 = offline
msg *message_list;
int message_count;
}
And one service we need to implement is to pull a list of all currently connected users. I have written this function for that task.
void all_connected(char buf[2300])
{
printf("\n entering all_connected for %d iterations",user_count);
int i, count = 1;
char tmp[25];
for (i=0; i<user_count; i++)
{
if(users[i] -> online == 1)
{
sprintf(tmp, "\n\t%d. %s", count++, users[i] -> username);
strcat(buf, tmp);
}
}
printf("\n exiting all_connected");
}
Now for some weird reason, when I call this function when the service is requested, it prints the first printf (entering all_connected for x iterations); but it doesn't print the one that I've put on the last line.
Does this mean that the function is getting stuck on some line? I checked and it is iterating 'user_count' times, but never coming on the last line.
What might be a reason for this happening?

This format string "\n\t%d. %s" (assuming up to 20 characters per user) will need a 26-bytes (ASCII) buffer. Here's why:
1 or 2 bytes for the "\n" (depending on the system)
up to 2 bytes for "%d" (presuming you count up to 99)
2 bytes for ". "
up to 20 bytes for "%s"
Your temporary buffer char tmp[25]; is too narrow - has to be at least 26 bytes big (counting the NULL-terminator).
If you have a list of 100 users that would require a total buffer of at least 2601 bytes but from the looks of it you are only providing the function with the buffer of the size 2300. Side note, just specifying the function's input parameter as being char buf[2300] doesn't do anything to actually allocate that buffer. You'd have to make sure you supply the necessary buffer when you call your function.
The reason you are not getting the second printf() is because your program terminates before reaching that point. The reason for termination is memory access violation - that happens when you try to write something into the memory that doesn't belong to your buffers (either a small one or the bug one)

Related

My code runs smoothly to the end in Linux but ends abruptly in Windows

I am new to coding. As a practice problem, I wrote a program to sort strings as alphabetically, as in a dictionary. My program takes as input:
(a) The number of strings the user has in mind
and (b) The strings, one by one, each terminated by pressing the enter key.
It stores the initial input in a buffer array of size MAXSTR and simultaneously counts the number of characters. Then it creates allocates memory of requisite size at memory location input[i] and copies the buffer to that location. It also creates an index array, with array elements having value of 0, 1, 2 ... each corresponding to one the 0th string, 1st string, 2nd string ... and so on. The function dictsort sorts the index array based on the alphabetical position of the corresponding string.
My program runs smoothly on Linux machines. However, on Windows, it compiles alright, but while running the executable, it ends abruptly while executing the line "input[i]=(char)malloc(jsizeof(char));". If any of you guys can indicate what is happening it will be of great help. Note that my problem is with the main function only. The sorting functions work fine, and hence those are not either included or commented out from below code.
#define MAX 10000
#define MAXSTR 100
#include<stdio.h>
#include<stdlib.h>
//int dictsort(char **mainarray, size_t *indexarray, size_t elementcount);
//int strcompare(char* str1, char* str2);
//int getvalue(int input);
int main(void){
size_t n, i, j,k;
char buffer[MAXSTR];
int c;
size_t *index;
char **input;
printf("Input number of elements:\t");
scanf("%ld", &n);
n=n<MAX ? n : MAX;
index=(size_t*)malloc(n*sizeof(size_t));
getchar(); // flush the newline after scanf
for(i=0;i<n;++i){
index[i]=i;
printf("Input element %ld:\t", i+1);
j=0;
while(((c=getchar())!=EOF) && (c!='\n') && (c!='\0') && (j<MAXSTR-1)){
buffer[j]=c;
++j;
}
buffer[j]='\0';
printf("Upto 1\n"); //program comes upto here
input[i]=(char*)malloc(j*sizeof(char));
printf("Upto 2\n"); //never reaches here
for(k=0;k<j+1;++k){
input[i][k]=buffer[k];
}
}
//dictsort(input, index, n); //disabled for debugging
printf("The sorted array is: \n");
for (i=0;i<n;++i){
printf("%s ", input[index[i]]);
}
for(i=0;i<n;++i){
free(input[i]);
}
free(index);
return 0;
}
First error:
You are allocating memory for index and input[i], but not for input itself. This means that you are dereferencing an uninitialized pointer on the following line:
input[i]=(char*)malloc(j*sizeof(char));
This will invoke undefined behavior, which explains why it crashes on that line on one platform, but works on another platform.
Second error:
The line
input[i]=(char*)malloc(j*sizeof(char));
will not allocate sufficient space for storing the string. Since j is the size of the string without the terminating null character, you must allocate j+1 bytes instead.
Due to not allocating a sufficient number of bytes for the string, the following loop will access the memory buffer input[i] out of bounds:
for(k=0;k<j+1;++k){
input[i][k]=buffer[k];
}
This will invoke undefined behavior.
Third error:
Another source of undefined behavior in your program is the following line:
scanf("%ld", &n);
The correct conversion format specifier for size_t is %zu, not %ld. See the documentation of the function scanf for further information.
On 64-bit Microsoft Windows, a long has a width of 4 bytes, but a size_t has a width of 8 bytes. Therefore, because you are using the format specifier for long instead of size_t, the function scanf is probably only writing to half of the variable n, leaving the other half of the variable uninitialized. This is likely to cause trouble when you read the value of n later in the program.
Most compilers will warn you about using the wrong scanf conversion format specifiers, assuming that you enable all compiler warnings. You may want to read this:
Why should I always enable compiler warnings?

What is the point of assigning the size of a string?

For an instance if I store ABCDE from scanf function, the later printf function gives me ABCDE as output. So what is the point of assigning the size of the string(Here 4).
#include <stdio.h>
int main() {
int c[4];
printf("Enter your name:");
scanf("%s",c);
printf("Your Name is:%s",c);
return 0;
}
I'll start with, don't use int array to store strings!
int c[4] allocates an array of 4 integers. An int is typically 4 bytes, so usually this would be 16 bytes (but might be 8 or 32 or something else on some platforms).
Then, you use this allocation first to read characters with scanf. If you enter ABCDE, it uses up 6 characters (there is an extra 0 byte at the end of the string marking the end, which needs space too), which happens to fit into the memory reserved for array of 4 integers. Now you could be really unlucky and have a platform where int has a so called "trap representation", which would cause your program to crash. But, if you are not writing the code for some very exotic device, there won't be. Now it just so happens, that this code is going to work, for the same reason memcpy is going to work: char type is special in C, and allows copying bytes to and from different types.
Same special treatment happens, when you print the int[4] array with printf using %s format. It works, because char is special.
This also demonstrates how very unsafe scanf and printf are. They happily accept c you give them, and assume it is a char array with valid size and data.
But, don't do this. If you want to store a string, use char array. Correct code for this would be:
#include <stdio.h>
int main() {
char c[16]; // fits 15 characters plus terminating 0
printf("Enter your name:");
int items = scanf("%15s",c); // note: added maximum characters
// scanf returns number of items read successfully, *always* check that!
if (items != 1) {
return 1; // exit with error, maybe add printing error message
}
printf("Your Name is: %s\n",c); // note added newline, just as an example
return 0;
}
The size of an array must be defined while declaring a C String variable because it is used to calculate how many characters are going to be stored inside the string variable and thus how much memory will be reserved for your string. If you exceed that amount the result is undefined behavior.
You have used int c , not char c . In C, a char is only 1 byte long, while a int is 4 bytes. That's why you didn't face any issues.
(Simplifying a fair amount)
When you initialize that array of length 4, C goes and finds a free spot in memory that has enough consecutive space to store 4 integers. But if you try to set c[4] to something, C will write that thing in the memory just after your array. Who knows what’s there? That might not be free, so you might be overwriting something important (generally bad). Also, if you do some stuff, and then come back, something else might’ve used that memory slot (properly) and overwritten your data, replacing it with bizarre, unrelated, and useless (to you) data.
In C language the last of the string is '\0'.
If you print with the below function, you can see the last character of the string.
scanf("%s", c); add the last character, '\0'.
So, if you use another function, getc, getch .., you should consider adding the laster character by yourself.
#include<stdio.h>
#include<string.h>
int main(){
char c[4+1]; // You should add +1 for the '\0' character.
char *p;
int len;
printf("Enter your name:");
scanf("%s", c);
len = strlen(c);
printf("Your Name is:%s (%d)\n", c, len);
p = c;
do {
printf("%x\n", *(p++));
} while((len--)+1);
return 0;
}
Enter your name:1234
Your Name is:1234 (4)
31
32
33
34
0 --> last character added by scanf("%s);
ffffffae --> garbage

I received the error message: Run-Time Check Failure #2. Stack around the variable was corrupted. However, I was not out of bounds of any array

I've been doing some exercise with structures to prepare for my upcoming exams, and I've run into a bit of trouble with this code.
// Creates a structure of type 'person' with a first name (nameF), last name (nameL), and the age (age)
typedef struct {
char nameF[20];
int age;
char nameL[40];
}person;
// Main function
int main() {
person ppl[2]; // We are creating 3 "people", whose information shall be printed into the file
// This loop takes user input to create the names and ages of 3 people
int i;
for (i = 0; i <= 2; i++) {
printf("\nEnter first name %d: ", i+1);
scanf("%s", &ppl[i].nameF);
printf("%s\n", ppl[i].nameF);
}
printf("It worked\n");
system("pause");
return 0;
}
It runs fine, but when the program exits, I keep receiving an error message from the Debugger that states: "Run-Time Check Failure #2. Stack around the variable 'ppl' was corrupted."
So I looked it up on Stack Overflow, this error appears when you go outside the bounds of a string. I don't understand where in my code I'm going out of bounds.
Here's an example of the output:
Enter first name 1: 'Adolfo'
Adolfo
Enter first name 2: 'Cecilia'
Cecilia
Enter first name 3: 'Tim'
Tim
Press any key to continue...
And then the error message pops up.
As you can see none of my inputs exceed the maximum amount of characters for the variable 'nameF', so there should be no reason for me to receive the error.
I saw someone on Stack Overflow mention that instead of making a character array:
char nameF[20];
One should instead write use dynamic memory allocation:
char * nameF = malloc(<enough bites to support any input);
Unfortunately, I don;t quite have a grasp of memory allocation yet, and when I attempted this code, I received all sorts of other errors, and my program wouldn't even run.
What is the mistake?
Also, I am not sure if this information is important, but I wrote this code using Visual Studio in C.
Edit: "char * nameF[20]" to "char nameF[20]" that asterisk was a leftover from my previous attempts at fixing the code, sorry.
Why are you allocating two structures then filling it with three responses?
Also, scanf is very dangerous as it can easily be abused to overwrite past a buffer. Look for routines (or write one) that limits the input to the length of the string.
hint: scanf man page might lead you to a better version.
Not meant as an answer, just made some adaptions allowing you to continue your work:
typedef struct {
char nameF[20]; // may take on 19 characters (+ string terminating char)
int age;
char nameL[40];
}person;
int main() {
person ppl[3]; // 3, not 2.
int i;
for (i = 0; i <= 2; i++) {
printf("\nEnter first name %d: ", i+1);
scanf("%s", ppl[i].nameF); // removed the &
printf("%s\n", ppl[i].nameF);
}
printf("It worked\n");
system("pause");
return 0;
}

Consecutive scanf is adding up strings [duplicate]

This question already has answers here:
How to prevent scanf causing a buffer overflow in C?
(6 answers)
Closed 6 years ago.
I've been having a problem with a very simple program and I really don't know why. There is a struct for a person:
typedef struct {
char name[50];
char p_id[11];
char cel[11];
int by;
int id;
} Person;
Now, there is another struct which stands for the list of contacts:
typedef struct {
Person * people;
} lContacts;
I've been trying to include the person's data to it, and add that person to the contact list. The person is being added normally, so I won't post the code here, but there is something wrong happening when I read the string:
void include(lContacts * myContacts)
{
Person p;
scanf("%s", p.name);
scanf("%d", &p.by); //birth year
scanf("%s", p.p_id);
printf("TEST P_ID: %s\n\n", p.p_id);
scanf("%s", p.cel);
printf("TEST P_ID AGAIN: %s\n\n", p.p_id);
myContacts->people[index]=p; //don't worry about the index, there is a piece of code I'm omitting to make it easier to read, just assume it is right.
}
}
Notice that I have a print test there, because when I listed my contacts, the contact p_id had itself concatenated with the cel, so I printed the whole code until I found the mistake was there.
Here is a input example:
Name
1991
11111111111
<console prints| TEST P_ID: 11111111111>
22222222222
<console prints| TEST P_ID AGAIN: 1111111111122222222222>
however, if I print p.cel, it is correctly printed
<console prints 22222222222>
Any ideas? Maybe I should use '&' when scanning strings? (I read about it and the way I understood, there is no need.. is that right?)
This is actually a very minute mistake here. Basically, you are experiencing a Buffer Overflow in the string p.p_id.
When you input the value for p.p_id as 11111111111 (11 times 1), you must realise that the actual capacity for the p_id string is declared as just 11 which must include the NULL character at the end.
If you assign 11111111111 to p_id there will be no space left for the NULL character in that string and so there will NOT be any at its end.
When you input the value for next member string of the structure, the same happens there, too.
Now, when you are trying to print the value of p.p_id the value will print until a '\0' (NULL character) is found in the string. But, there is none here, so the next string will start printing! (The buffer or string p_id overflows)
This is happening due to the member alignment done in structures in C. The next string will be stored in a consecutive memory cell, so the printing will continue. (If there was a third consecutive string member, then due to the buffer overflow in the second string, it will print too!)
But, the printing stops after second string because either there is no data in the next consecutive memory cell due to certain struct alignment or there may be an actual 0 value in the next cell which is interpreted as NULL character.
To avoid, either use a larger size for the character array or use dynamically allocated strings.
As #skrtbhtngr pointed out, you have a buffer overflow. In order to prevent this in the future, you should use fgets instead of scanf on unknown string inputs. This example will exit(1) if the input is corrupted.
int getsafestring(char* s, int maxlen)
{
if(fgets(s,maxlen,stdin) == NULL) return 1; // read error
if(strlen(s) == 0) return 2; // other read error
if(s[strlen(s)-1] !='\n') return 3; // buffer overflow error
s[strlen(s)-1]=0; // replace newline with null
return 0;
}
if(Getsafestring(p.name,sizeof(p.name))) exit(1);
if(scanf("%d", &p.by) != 1) exit(1);
if(getsafestring(p.p_id,sizeof(p.p_id))) exit(1);
if(getsafestring(p.cel,sizeof(p.cel))) exit(1);

Appending an output file in C

I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and the first case is also a success. But the problem is in the second case and the way my file is being appended. The program is as follows:-
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAX 6
main()
{
int cal(char *ptr);
int a,b;
char *comet,*group;
FILE *fptr;
comet=malloc(6*sizeof(char));
group=malloc(6*sizeof(char));
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
fptr=fopen("ride.out","a+"); (1)
//fptr=fopen("ride.txt","a+"); (2)
if(a==b)
fprintf(fptr,"GO\n"); (3)
//printf("GO\n"); (4)
else
fprintf(fptr,"STAY\n"); (5)
//printf("STAY\n"); (6)
fclose(fptr);
return 0;
}
int cal(char *ptr)
{
int c,prod=1,mod;
while(*ptr)
{
c=(*ptr++)-'A'+1;
prod=prod*c;
}
mod=prod%47;
return mod;
}
OUTPUT:-
The first case is the set two strings:-
COMETQ
HVNGAT
and the second case is given in the error notification itself.
If I remove the comment symbols from (2) and put it on (1), then the program is working fine because I can see the contents of the file and they appear just as the grader system wants. It isn't happening for the actual statement of (1). The comments of line (4) and (6) are also fine but not the line (1). I am not able figure this out. Any help?
First a few notes:
main(): a decent main is either:
int main(void)
or
int main(int argc, char *argv[])
Using malloc() you should always check if it returns NULL, aka fail, or not.
Always free() malloc'ed objects.
Everyone has his/hers/its own coding style. I have found this to be invaluable when it comes to C coding. Using it as a base for many other's to. Point being structured code is so much easier to read, debug, decode, etc.
More in detail on your code:
Signature of cal()
First line in main you declare the signature for cal(). Though this works you would probably put that above main, or put the cal() function in entirety above main.
Max length
You have a define #define MAX 6 that you never use. If it is maximum six characters and you read a string, you also have to account for the trailing zero.
E.g. from cplusplus.com scanf:
specifier 's': Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
Thus:
#define MAX_LEN_NAME 7
...
comet = malloc(sizeof(char) * MAX_LEN_NAME);
As it is good to learn to use malloc() there is nothing wrong about doing it like this here. But as it is as simple as it is you'd probably want to use:
char comet[MAX_LEN_NAME] = {0};
char group[MAX_LEN_NAME] = {0};
instead. At least: if using malloc then check for success and free when done, else use static array.
Safer scanf()
scanf() given "%s" does not stop reading at size of target buffer - it continues reading and writing the data to consecutive addresses in memory until it reads a white space.
E.g.:
/* data stream = "USACOeRRORbLAHbLAH NOP" */
comet = malloc(szieof(char) * 7);
scanf("%s", buf);
In memory we would have:
Address (example)
0x00000f comet[0]
0x000010 comet[1]
0x000011 comet[2]
0x000012 comet[3]
0x000013 comet[4]
0x000014 comet[5]
0x000015 comet[6]
0x000016 comet[7]
0x000017 /* Anything; Here e.g. group starts, or perhaps fptr */
0x000018 /* Anything; */
0x000019 /* Anything; */
...
And when reading the proposed stream/string above we would not read USACOe in to comet but we would continue reading beyond the range of comet. In other words (might) overwriting other variables etc. This might sound stupid but as C is a low level language this is one of the things you have to know. And as you learn more you'll most probably also learn to love the power of it :)
To prevent this you could limit the read by e.g. using maximum length + [what to read]. E.g:
scanf("%6[A-Z]", comet);
| | |
| | +------- Write to `comet`
| +-------------- Read only A to Z
+---------------- Read maximum 6 entities
Input data
Reading your expected result, your errors, your (N) comments etc. it sound like you should have a input file as well as an output file.
As your code is now it relies on reading data from standard input, aka stdin. Thus you also use scanf(). I suspect you should read from file with fscanf() instead.
So: something like:
FILE *fptr_in;
char *file_data = "ride.in";
int res;
...
if ((fptr_in = fopen(file_data, "r")) == NULL) {
fprintf(stderr, "Unable to open %s for reading.\n", file_data);
return 1; /* error code returned by program */
}
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", comet)) != 1) {
fprintf(stderr, "Read comet failed. Got %d.\n", res);
return 2;
}
b = cal(comet);
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", group)) != 1) {
fprintf(stderr, "Read group failed. Got %d.\n", res);
return 2;
}
...
The cal() function
First of, the naming. Say this was the beginning of a project that eventually would result in multiple files and thousand of lines of code. You would probably not have a function named cal(). Learn to give functions good names. The above link about coding style gives some points. IMHO do this in small projects as well. It is a good exercise that makes it easier when you write on bigger to huge ones. Name it e.g. cprod_mod_47().
Then the mod variable (and might c) is superfluous. An alternative could be:
int cprod_mod_47(char *str)
{
int prod = 1;
while (*str)
prod *= *(str++) - 'A' + 1;
return prod % 47;
}
Some more general suggestions
When compiling use many warning and error options. E.g. if using gcc say:
$ gcc -Wall -Wextra -pedantic -std=c89 -o my_prog my_prog.c
This is tremendous amount of help. Further is the use of tools like valgrind and gdb invaluable.

Resources