This C program I am making reads a set of chars from the command line and stores them using an array (argv[]) like so
main (int argc, char *argv[]) {
int temp;
/*prevents no arguments*/
if (argc==1){
printf("Usage;\t[0 < integers < 9] [operators]\n");
exit(0);
}
int i;
for (i = 0 ; i<argc; i++){
temp = argv[i] - '0';
printf("this is char %d ; %d\n",i, temp);
}
}
But all I get after running it in the command line like so;
program 2 4 1 - +
is random garbage
this is char 0 ; -4195956
this is char 1 ; -4195950
this is char 2 ; -4195948
this is char 3 ; -4195946
this is char 4 ; -4195944
this is char 5 ; -4195942
Is there something wrong with the way I'm casting temp? Or am I just getting the idea of pointers (in *argv[]) wrong?
argv[i] - is just a pointer to C string; you need first element:
temp = argv[i][0] - '0';
char *argv[]
argv is an array of pointers to char. So argv[X] is a pointer to char (for suitable X). So argv[X] - some_integral_value is pointer arithmetic, and returns a pointer (if that subtraction is defined).
To access the first element, you need argv[X][0].
Please note that argv[0] is not the first argument but (usually) the program name. Arguments start at argv[1].
Each element of argv is a string of characters, not a specific character. argv is a multi-dimensional array, and you're only indexing the first dimension. You need to take the first (zeroth) element of each nested array:
temp = argv[i][0] - '0';
For numbers, you can use function atoi(str) as following:
temp = atoi(argv[i]);
Code:
for (i = 0 ; i<argc; i++){
if (argv[i][0] < '0' || argv[i][0] > '9')
printf("Operator = %s\n", argv[i]);
else {
temp = atoi(argv[i]);
printf("this is char %d ; %d\n",i, temp);
}
}
You can use separate char array to store operators..
Related
First function changes big letter to small. In main I need to have five strings and with function konvertuj I have to go through that array and check for each letter if it's big and convert it to small. The point is that I don't know how to access each character of string in the function. (It's study example so it has to be done with these predefined functions.
char v2m(char z){
char m = z + 0x20;
return m;
}
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
int main(){
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
for (int i = 0; i < 5; i++)
{
int d = -1;
while(niz[i][++d]);
konvertuj(&niz[i], d);
printf("%s ", niz[i]);
}
}
v2m - no need of the variable m
konvertuj no need to iterate through the same letters all over again. You want to convert 1 letter as you iterate in main. Your condition is wrong as you will ignore 'A' and 'Z'
Pointer to pointer does not have allocated space to accommodate 5 pointers. You need to allocate this space. In your code is it UB.
3.a You assign the pointers to the string literals. Attempt to modify the string literal invokes Undefined Behaviour. In my code, I use compound literals which are modifiable.
3.b use correct type for indexes (size_t).
char v2m(char z){
return z + 0x20;
}
void konvertuj(char *niz, size_t n){
if(niz[n] >= 'A' && niz[n] <= 'Z')
niz[n] = v2m(niz[n]);
}
int main(void){
char **niz = malloc(5 * sizeof((*niz)));
niz[0] = (char[]){"Voda"};
niz[1] = (char[]){"KraISSa"};
niz[2] = (char[]){"somsssR"};
niz[3] = (char[]){"aaaaa"};
niz[4] = (char[]){"WeWeWeW"};
for (size_t i = 0; i < 5; i++)
{
size_t d = 0;
while(niz[i][d])
konvertuj(niz[i], d++);
printf("%s ", niz[i]);
}
}
As I( understand you need to keep the function names types and parameters
Sure, it is possible to write it the way you did, but you have to build things accordingly and you did not.
And there some errors, anyway. I will try to show you some points. Please be patient.
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
In C in general you can not just assign a value to a string. You use something like
strcpy( niz[0], "ANewValue");
v2m()
Instead of
char v2m(char z){
char m = z + 0x20;
return m;
}
You can just write
char v2m(char z) { return z + 0x20; }
There is no need to declare a char just for holding the return value.
IIUC you can not change the function prototypes...
konvertuj()
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
here I believe you missed the point that the function will receive just a string each time is called, not the whole vector of strings.
The int n is just the length of the string, and even if you could not use strlen() to compute it, it should probably be done inside the function.
but I believe you can not change this prototype also.
note that you are not including 'A' and 'Z' in your test. Maybe you should use '>=' and '<=' in the tests.
since the function gets a single string each call, you must remove many of the '*'
note that you had the strings declared as literals, CONSTANTS that you can not change. The first time you try to change a letter your program will abort
This one below should work and you can compare:
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
main()
Instead of
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
You could write just
char niz[][15] =
{
"Voda",
"KraISSa",
"somsssR",
"aaaaa",
"WeWeWeW"
};
In C just the last dimension must be declared, e.g. the '15' above, since the compiler can determine here the other dimension. And this way you can initialize all of them directly. But in order to change one in the code you need to use a loop and replace letter by letter, or call
strcpy( niz[0], "ANewValue");
Also you can initialize just a few of them, and even out of order, as in
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
and this is really handy.
Computing the number of strings
Note that you can compute the number of strings and even assign "TheLastValue" to the last one, by writing
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
What if char** niz is needed?
This is a really common paradigm in C and C++, and it is very useful. You may recall that the prototype for main() is
int main( int argc, char** argc)
for every C program, so you can see how common it is.
Fact is that when you declare niz as char** you are declaring a single variable. What is niz? Well, it is a pointer to a pointer to a char.
niz is char**
*niz is char*
**niz is a single char
But niz is a pointer and it is pointing to nowhere when declared. In your case you want niz pointing to not one but FIVE strings. And if you do nothing the program will abort the first time you try to use it...
You need to build this:
A string is a pointer to the first char, char*
so niz needs to point to an area capable of holding 5 pointers to char
What about the size of a pointer to char? That is easy: sizeof(char*)
Then you need to make each niz[x] point to the required string.
It will not happen by itself. You must build each and every one.
An example: building char** sample from niz as declared above
The code below builds sample as an array of pointers, pointing to the same strings declared and allocated for niz[][] above, and them prints them all
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
Note that the strings already exists and we are just pointing to them. A new reference only.
A new example: building char** copy as a full copy of niz
It is very very important to see the difference here: copy points to an array of pointers, but each pointer points to a copy of the corresponding string declared in niz and referenced in the sample array.
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
// large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
Note: it is in general not recommended to cast the pointers return by malloc() in C, as in the lines
copy = (char**) malloc(area);
// or
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
I just do not care and prefer to write all them down explicitly, as a reminder to myself of what is what. Sure, in C++ you must declare this, but is is rare to allocate memory this way in C++ since C++11. Fell free to use whatever rule you see fit
A complete example
This is the output
PS C:\src\ifdef> gcc -o teste -Wall -Wextra -Wpedantic -std=c17 so210126.c
PS C:\src\ifdef> ./teste
Total of 8 values
Before: Voda (4)
After: voda
Before: KraISSa (7)
After: kraissa
Before: somsssR (7)
After: somsssr
Before: aaaaa (5)
After: aaaaa
Before: WeWeWeW (7)
After: wewewew
Before: AomsssZ (7)
After: aomsssz
Before: A (1)
After: a
Before: TheLastValue (12)
After: thelastvalue
=> Printing the 8 strings using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
=> Printing the 8 copies using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
PS C:\src\ifdef>
I compiled just on gcc 10.2 on Windows.
This is the example code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char v2m(char z) { return z + 0x20; }
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
int main(void)
{
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
for (int i = 0; i < n; i++)
{
int d = 0;
while ( niz[i][d] != 0) d+=1;
printf("Before: %s (%d)\n", niz[i], d);
konvertuj( niz[i], d );
printf("After: %s\n", niz[i]);
}
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) ); // large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
for( int i=0; i<n; i+=1) free(copy[i]); // destroy each string
free(copy); // destroy the array;
free(sample); // sample points to static memory...
return 0;
}
As for the very very long post: I wanted to leave an example of the
solution plus an example of the steps involved in order to build a char** vector from
existing strings and as an independend copy.
I am converting string arguments into ints I am having an issue where the first argument is not copying and converting to a string while the second argument is working just fine. I am removing the first character of the string array and printing out the rest of the string as an int.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(int argc, char *argv[])
{
char numcpy1[sizeof(argv[1])-1];
char numcpy2[sizeof(argv[2])-1];
int i, len1, len2;
int result1=0;
int result2=0;
//Access first character for base
printf("%c \n", argv[2][0]);
printf("%c \n", argv[3][0]);
//Remove first character for number1 and number 2
if(strlen(argv[2]) > 0)
{
strcpy(numcpy1, &(argv[2][1]));
}
else
{
strcpy(numcpy1, argv[2]);
}
len1 = strlen(numcpy1);
if(strlen(argv[3]) > 0)
{
strcpy(numcpy2, &(argv[3][1]));
}
else
{
strcpy(numcpy2, argv[3]);
}
len2 = strlen(numcpy2);
//Turn remaining string characters into an int
for(i=0; i<len1; i++)
{
result1 = result1 * 10 + ( numcpy1[i] - '0' );
}
for(i=0; i<len2; i++)
{
result2 = result2 * 10 + ( numcpy2[i] - '0' );
}
printf("%d \n", result1);
printf("%d \n", result2);
return 0;
}
Output:
b
b
-4844
1010
What I want:
b
b
1000
1010
The sizeof operator does not give you the length of a string, as you seem to think it does. It tell you the size of the datatype. Since argv[2] is a char *, this evaluates to the size of this pointer, most likely 4 or 8 depending on the system.
If the string in question is longer than this value, you end up writing past the end of the array. This invokes undefined behavior, which in your case manifests as an unexpected result.
If you want the length of the string, use the strlen function instead. Also, you need to add one more byte. Strings in C are null terminated, so you need space for the null byte that marks the end of the string.
char numcpy1[strlen(argv[2])];
char numcpy2[strlen(argv[3])];
Also note that we don't need to add 1 to each of these since the first character in each string isn't copied.
You need to change
char numcpy1[sizeof(argv[1])-1];
to
char numcpy1[strlen(argv[1]) + 1];
Ditto for numcpy2
I think instead of copying the numbers you could work more easily with pointers. Thereby, you don't have to think about memory allocation and copying the values just for the sake of converting them into an integer value:
const char *numcpy1 = argv[2][0]=='\0' ? argv[2] : argv[2]+1;
...
I'm new to C and trying to figure out arrays and command line arguments. I have:
int main(int argc, int **argv) {
int vals[8];
for(int i = 0;i < 8;i = i + 1) {
vals[i] = atoi(argv[i]);
printf("%d", vals[i]);
}
}
I call it with ./file 1 2 3 4 5 6 7 8 and I would expect it to spit out 12345678, but instead, it spits out 01234567 which to me says that it's just printing the array positions. How do I get to actually print/access the value of vals[i], and/or make sure that the command line value is actually being properly assigned?
Thanks in advance.
Start with argv[1] In order to exclude the first element of argv which is the program name. A simple way to do this is to increment argv at the top of the program.
int main(int argc, char **argv) {
argv++; /* argv[0] is the program name */
int vals[8];
for(int i = 0;i < 8;i = i + 1) {
vals[i] = atoi(argv[i]);
printf("%d", vals[i]);
}
}
On a side note, you should check the value of argc prior to accessing elements at index i in argv
argv [0] is the name of the program.
The arguments start at 1. You should also get in the habit of using argc in loops.
int main(int argc, int *argv[])
{
for(int i = 1 ; i < argc ; ++ i )
{
int val = atoi(argv[i]);
printf("%d", val);
}
}
This is part of an assignment to complete a word search. I have to use command line arguments to search a predetermined 2D array. I need to searh only the Horizontal (left to right), Diagnal (top-left to bottom-right), and Vertical (top to bottom).
I'll write the Diag and Vert once I understand the pointer issue better.
I get
warning: comparison between pointer and integer
This happens at the following if-statement
if (argv[count] == g[i][j]){
Why do I get the warning and what am I missing in my understanding of pointers that prevents me from doing this.
I've tried different variations of *g and (int star)g with worse results than just the warning.
I need to have warning free code for turn-in.
Thank You for helping the new people.
#include <stdio.h>
#define ROW 3
#define COL 4
#define TRUE 1
#define FALSE 0
int checkHoriz(char *data, char *data2);
main(int argc, char *argv[]){
int count, i, j, rowValue, colValue;
char g[ROW][COL] = {{'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'}};
count=1;
if(argc>1){
for(i=0; i<ROW; i++){
for(j=0; j<COL; j++){
if (argv[count] == g[i][j]){
rowValue = i;
colValue = j;
if(checkHoriz(argv[count],g[i][j]) ==TRUE){
printf("%s appears horizontally starting # g[%d]{%d]. \n", argv[count], i,j);
}
}
}
}
}else{
printf("No arguments were entered.\n");
}
}
int checkHoriz(char *data, char *data2){
int i = 0;
while (data == data2 && data!=' ' && data2 != '\0'){
data++;
data2++;
}
if(data2 == '\0'){
return 1;
}else{
return 0;
}
}
argv is an array of strings; a char** and g is an array of char arrays; a char[][].
Therefore, argv[count] is of type char* (a string), and g[i][j] is of type char. You're comparing a pointer to a single char, an integer type. This is what the warning is telling you.
If you want to search for the chars of g inside of argv[count], then you're going to need to dereference argv[count] one level further, and work with the individual chars in the range of argv[count][0] to argv[count][strlen(argv[count]) - 1].
My program grabs command line arguements with argc and argv[]. My question is how can I find the length of argv[1][i].
My code that grabs length of argv[]
int my_strlen(char input[]){
int len = 0;
while(input[len] != '\0'){
++len;
}
return len;
}
but when I try to find argv[1][len] I get a subscripted value is neither array nor pointer:
my attempt
int my_strlen(char input[]){
int len = 0;
while((input[1][len] - '0') != '\0'){
++len;
}
return len;
}
FULL CODE:
#include <stdio.h>
#include <math.h>
int my_strlen(char input[]);
int main(int argc, char *argv[]){
int length = 0;
length = my_strlen(argv[1]);
long numberArr[length];
int i, j;
for(i = 0; i < length; i++){
numberArr[i] = argv[1][i] - '0';
}
return 0;
}
int my_strlen(char input[]){
int len = 0;
while((input[1][len] - '0') != '\0'){
++len;
}
return len;
}
Thanks for any help in advance!
I think you're confused about the argv content. The OS will pass a number of ASCIIZ strings, such that invoking my_program with arguments ala...
my_program first second third
...is similar to having the following declaration in your program...
int argc = 4;
const char* argv[4] = { "my_program", "first", "second", "third" };
Hence, when you index into argv[1][i] you're getting the i-th character in the string "first". That's only valid for values of i between 0 (which yields 'f'), and 5 (which indexes to the terminating NUL character '\0').
So, there no two-dimensional N*M array, but there is an array of pointers-to-(array-of-char). You can invoke the normal strlen() function as in strlen(argv[1]) to find out the number of characters in each argument. Only argc tells you the total number of elements in argv.
Does that help?
In main, you're passing argv[1] to my_strlen. That means my_strlen just receives a normal, single-dimension string. It doesn't need to do input[1][len], just input[len].