C - Cursor placement influencing program - c

I'm writing a C program that reads a string in the form of a table from a .txt file, counts rows and columns in it and prints the table to a different .txt file.
Here's the input table:
Something.Something-Something
Something.Something-Something
Something.Something-Something
Something.Something-Something
Here's how I run the program:
gcc -Wall -Wextra -Werror -o main main.c
./main <tabin.txt >tabout.txt
The program itself:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ROW_LENGTH 10240
int rowNumber(char buffer[ROW_LENGTH], int i, int rowcounter) {
if(buffer[i] == '\n')
++rowcounter;
return rowcounter;
}
int colNumber(char buffer[ROW_LENGTH], int i, int colcounter) {
if(!isalnum(buffer[i]))
++colcounter;
return colcounter;
}
int main() {
char buffer[ROW_LENGTH];
int rowcounter = 0;
int colcounter = 0;
while(fgets(buffer, ROW_LENGTH, stdin) != NULL)
for(int i = 0; buffer[i]; i++) {
rowcounter = rowNumber(buffer, i, rowcounter);
colcounter = colNumber(buffer, i, colcounter);
printf("%c", buffer[i]);
}
printf("\n%d", rowcounter);
printf("\n%d", colcounter);
return 0;
}
And know the part I don't understand. I'm using CLion on Ubuntu. When I place the cursor right after the last g and save, I get
3
11
However when place the cursor on the first character of the next line, I get
4
12
What are the ways I can change my code so cursor position doesn't influence the results I get?

Related

Indexing function for dynamic arrays in c

I am writing this piece of code which works without any errors but when I run it with valgrind it throws errors that Conditional jump or move depends on uninitialized value which is caused by the while loop trying to access the third element in the array
My question is can I use the function get_index() since it does not show any warnings or errors when compiling with gcc -g -Wall -pedantic main.c and outputs the same index as the idx which is declared globally
#include <stdio.h>
#include <stdlib.h>
#define L 3
int *ptr;
int idx=0; // index
int get_index()
{
int x=0;
while(ptr[x])
x++;
return x;
}
void add_elem()
{
printf("Enter your number :\n");
scanf("%d",&ptr[idx]);
idx++;
}
int main(void) {
ptr = (int*)malloc(sizeof(int));
add_elem();
add_elem();
printf("Current index : %d\n",get_index());
printf("Original index : %d\n",idx);
return 0;
}

multifile direct compile ok, direct compile error

There are 3 files(generator.c, generator.h and main.c).
generator.c: There is only 1 function (gen fun) which is used to generate an array to store 10 random-generate numbers in generator.c.
generator.h:Declaration of generator.c.
main.c: There is only 1 function (main fun) in main.c which is used to print the number generated previously.
If generator.c is included in main.c and I compile it directly by execute "gcc main.c". The result is ok.
But while I compile it using " gcc -c generator.h, gcc -c main.c, gcc generator.o main.o ", it reported a warning "warning: assignment makes pointer from integer without a cast" at " p = gen(arr); " sentence in main funciton. And the final result was "Segmentation fault (core dumped)". The debug information showed "Cannot access memory at address" if i try to visit the value of pointer *p(i.e. array[0]) in the while loop of main function.
//////generator.c///////
int * gen( int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
srand( (unsigned)((time)(NULL)));
while (i< len)
{
*p = rand() % ( len +1) + 0;
i ++;
p++;
}
return arr;
}
//////generator.h//////
int * gen( int arr[]);
//////main.c///////
int main(void)
{
int i = 0;
int arr[10]={0};
int * p;
p = gen(arr);
while (i < 10)
{
printf("output is %d\n",*p);// Segmentation fault (core dumped)
i++;
p++;
}
return 0;
}
Based on the addition to your question, it appears you are confused about how to include generator.h and then to compile the code. First your generator.h should be:
//////generator.h//////
#ifndef GENERATOR_H
#define GENERATOR_H 1
int *gen (int arr[]);
#endif
(edit: added appropriate Header Guards to prevent multiple inclusion of generator.h)
Your generator.c would then be:
//////generator.c///////
#include <stdlib.h>
#include "generator.h"
int *gen (int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
while (i< len)
{
*p = rand() % len + 1;
i ++;
p++;
}
return arr;
}
And finally your main.c (I called it gen.c) would be:
//////main.c///////
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "generator.h"
int main(void)
{
int i = 0;
int arr[10]={0};
int *p;
srand( (unsigned)((time)(NULL)));
p = gen(arr);
while (i < 10)
{
printf ("output is %d\n",*p);
i++;
p++;
}
return 0;
}
Compile
$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast generator.c -o bin/gen gen.c
(note: I would also encourage adding -Wshadow as a normal part of your compile string as well to identify any shadowed variables)
Example Use/Output
$ ./bin/gen
output is 8
output is 1
output is 5
output is 4
output is 9
output is 5
output is 4
output is 6
output is 5
output is 6
Look things over and let me know if you have further questions.

C program behaves differently in gcc and llvm compiler

I wrote a program that consists of main and a function expand. The problem is that the code returns the intended result when compiled and run with Xcode (latest version) however when compiled and run with gcc compiler through terminal the code is stuck immediately after running (no warnings or errors!). This is the command I use to compile the code in the terminal:
gcc expand.c -o expand -Wall -pedantic -ansi
Below is my code. I have no idea what my problem is:
#include <stdio.h>
#define MAX_LEN 100
#define ATOI_GAP 48
void expand(char s1[], char s2[]);
int main()
{
int i;
char s2[MAX_LEN]; /* declare the target array */
char s1[4]; /* declare the source array */
s1[0] = 'a';
s1[1] = '-';
s1[2] = 'z';
s1[3] = '\0';
for(i = 0; i < MAX_LEN; ++i) { /* print s2 array */
printf("%d ", s2[i]);
}
expand(s1, s2);
for(i = 0; s2[i] != '\0'; ++i) { /* print s2 array */
printf("%c ", s2[i]);
}
return 0;
}
/* the function gets string s1 of format "letterX-letterY"
and fills the "-" with the consequent letters from letterX to
letterY. For example, if s1 = "a-d", then s2 will be "abcd"*/
void expand(char s1[], char s2[]) {
int start = s2[0] = s1[0]; /* the first letter of the array s2 is the same as that of the array s1 */
int stop = s1[2]; /* determine at which letter we need to stop */
int j;
printf("inside expand");
for(j = 1; j < stop - '0' - ATOI_GAP; ++j) {
s2[j] = ++start; /* fill in the gap */
}
s2[j] = '\0';
printf("finished expand");
}
Found the issue, I was incorrectly running the output C file. I previously exported the path with all my C output files, so to call the file in question I was just typing "filename" in the terminal. However, the exported path wasn't sourced properly so I wasn't getting any result. When I run the file as "./filename" everything is working.

Counting substrings in a string

I have the task to make a little program with pointers and I am facing a problem with const char*s. The program is meant to count the number of times that a sub-string appears in a main-string. Also, the different positions, where the sub-strings start, should be saved in a char** ptr. This is my little testing code:
#include <stdio.h>
#include <string.h>
main()
{
int i=-1;
int k=0;
char** ptr;
char* str="cucumber";
char* substr="cu";
while(strstr(str, substr)!=NULL)
{
i++;
ptr[i]=strstr(str, substr);
str = strpbrk(str, substr)+1;
k++;
}
printf("%i",k);
}
It should print 2, since the sub-string 'cu' appears 2 times in 'cucumber' - yet, my compiler tells me that I am using chars, when I should use constant ones. Except, I don't know how to do that.
The strstr() function requires them. What should I change?
// note:
// 1) correction to declaration of main()
// 2) addition of return statement
// 3) 'substr' is a poor name choice for a variable, as
// a) it looks like a C lib function (it is a ACL library function)
// b) it does not clearly convey what the variable contains
// 4) clutter in the 'while' loop removed
// 5) 'while' loop is replaced by a 'for' loop so more can be accomplished with less code
// 6) unneeded variables are eliminated
// 7) the 'for' loop stops when there is no possibility of further testStr occurrences
// 8) the printf() clearly indicates what is being printed
#include <stdio.h>
#include <string.h>
int main()
{
char* testStr="cucumber";
char* findStr="cu";
int k = 0;
for( int i=0; strlen(&testStr[i]) >= strlen(findStr); i++)
{
if( strstr(&testStr[i], findStr) != NULL)
{
k++;
}
}
printf("\nnumber of occurrences of %s in %s is %d\n", findStr, testStr, k);
return(0);
}
Allocate memory for storing the pointer values
#include <stdio.h>
#include <string.h>
#define MAX_SUB_STR 10
int main()
{
int i;
int k;
char* ptr[MAX_SUB_STR];
char* str="cucumber";
char* temp;
char* substr="cu";
i = 0;
k = 0;
temp = str;
while(strstr(temp, substr)!=NULL && k < MAX_SUB_STR)
{
ptr[k]=strstr(temp, substr);
temp = ptr[k] + strlen(substr);
k++;
}
printf("%i\n",k);
for (i = 0; i < k; i++)
printf("%p\n",ptr[i]);
return 0;
}

Random String Generator for Serial

I'm working on a programm that generates Serial Codes. I know there a several threads about this topic, but I wasn't able to solve my problem.
I want to create a string that looks like this:
3S6G-TXMS-RLP6-VE5N
I can only use uppercase letters and numbers and every group of characters (like 3S6G) can only have a max. of 2 numbers in it.
My real struggle is that I have to open the internet explorer and navigate it to a address that includes this serial. It should look like this one: https://www.mywebpage.com/serial/3S6G-TXMS-RLP6-VE5N.
I hope someone can help me, because I'm not able to find a solution by myself.
At the moment it doesn't run, when I start the program, it instantly crashes. Also I didn't implement the Internet Explorer yet.
My Code:
#include <stdio.h>
#include <windows.h>
#include <time.h>
static const char abc[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"123456789";
char Str[80];
char Str2[80];
char Str3[80];
char Str4[80];
char Stra[80];
unsigned int i;
int StringLength = sizeof(abc) -1;
char genRandom() {
return abc[rand() % StringLength];
}
int main()
{
SetConsoleTitle("Serial Generator");
srand(time(NULL));
for(i = 0; i < 4; i++) {
sprintf(Str, "%s", genRandom());
}
srand(time(NULL)-1);
for(i = 0; i < 4; i++) {
sprintf(Str2, "%s", genRandom());
}
srand(time(NULL)-2);
for(i = 0; i < 4; i++) {
sprintf(Str3, "%s", genRandom());
}
srand(time(NULL)-3);
for(i = 0; i < 4; i++) {
sprintf(Str4, "%s", genRandom());
}
sprintf(Stra, "%s-%s-%s-%s", Str, Str2, Str3, Str4);
printf("Your serial: \n");
printf("%s \n", Stra);
return 0;
}
I'm new to C, so please apologize if I ask dump questions.
Caveat:
I moved you code to a Linux box to test it there. I was able to successfully compile the code by (a) removing the #include <windows.h> line and (b) by removing the SetConsoleTitle("Serial Generator");
The compiler I'm using is gcc 4.8.2
OK, several things I see here
(1) you do not need to call srand more than once. srand seeds the random number generator. Really, really simplistically think of a huge table of random numbers and every time you make a call to rand you get the next number. srand picks where in that table you start. If you call srand multiple times in very quick succession, there is a good chance you will always be getting the same number.
(2) Why are all of your string arrays sized to 80? From what I can see, you will be sticking in four characters and allowing for the null terminator, you only need 5 bytes.
(3) Third, pay attention to compiler warnings ... they are there for a reason. When I compile you code I get the following warnings (I compiled with -g -ansi -Wall -pedantic):
dummy.c:19:5: warning: implicit declaration of function ‘rand’ [-Wimplicit-function-declaration]
return abc[rand() % StringLength];
^
dummy.c: In function ‘main’:
dummy.c:27:5: warning: implicit declaration of function ‘srand’ [-Wimplicit-function-declaration]
srand(time(NULL));
^
dummy.c:29:13: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
sprintf(Str, "%s", genRandom());
Both rand and srand are declared in <stdlib.h> and including this file got rid of the first two errors.
The next error (of which there are four of that form, I've only shown one), from taking the results of getRandom() which returns a char and then try to write it into the buffer Str1 using a string format specifier. Remember that a char data type is really an integer.
Additionally, sprintf(....) will overwrite what is in the buffer with the new string, so calling in a loop doesn't append strings, it will over write the contents. You can accomplish what you want with a loop that looks like this:
for(i = 0; i < 4; i++) {
Str2[i] = genRandom();
}
I suspect that this was the root cause of the error you initially reported.
(4) There is no reason for the variable i to have file scope, it should be moved inside main.
(5) You really don't need to use so many string variables. Consider this loop:
Stra[4] = Stra[9]=Stra[14] = '-'
for(i = 0; i < 4; i++) {
Stra[i] = genRandom();
Stra[5+i] = genRandom();
Stra[10+i] = genRandom();
Stra[15+i] = genRandom();
}
With all these changes and modifications, your program now looks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*#include <windows.h>*/
#include <time.h>
static const char abc[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
#define STRING_LEN 20
char Stra[STRING_LEN];
int StringLength = sizeof(abc) -1;
char genRandom() {
return abc[rand() % StringLength];
}
int main()
{
/* SetConsoleTitle("Serial Generator");*/
unsigned int i;
memset(Stra, '\0', STRING_LEN);
Stra[4] = Stra[9]=Stra[14] = '-';
for(i = 0; i < 4; i++) {
Stra[i] = genRandom();
Stra[5+i] = genRandom();
Stra[10+i] = genRandom();
Stra[15+i] = genRandom();
}
printf("Your serial: \n%s \n ", Stra);
return 0;
}
Running this program on my Linux system produces the following:
******#ubuntu:~$ gcc -ansi -pedantic -Wall dummy.c -o dummy
******#ubuntu:~$ ./dummy
Your serial:
II4U-LK6E-C6CN-FCMV
Finally, your code (and thus my answer) does not address the restriction of no more than 2 digits.

Resources