我认为C在未经许可的情况下生成空间



我用C编写了一个程序,该程序在另一个python脚本的帮助下从谷歌提供建议。当我最终编译并测试该程序时,发生了一件有趣的事情,结果python脚本的输出带有额外的空格。我在网上搜索了一下,但什么也找不到,所以我来了。

C代码:

#include <stdio.h>
#include <stdlib.h>

void search(){
system("clear");
char search[200];
char a;
char lsearch[800];
char esearch[2000];
printf("n*Suggestions for your Search*nnnn");
printf("> ");
system ("/bin/stty raw");
int i = 0;
while(i > -1) {
a = getchar();
if(a == ' ') {
system("clear");
search[i] = '!';
fflush(stdout);
snprintf(lsearch, 800, "cd python-bash-things && python3 rec.py %s",search);
fflush(stdout);
system(lsearch);
search[i] = ' ';
printf("nnn> %s",search);
i++;
continue;
}
else if(a == 3) 
return;
else if(a == 13) {
snprintf(esearch, 2000, "firefox -search '%s'",search);     
break;
}
search[i] = a;
i++;
}
system("clear");
system ("/bin/stty cooked");
system(esearch);
}
int main(){
search();
return 0;
}

Python代码:

#!/usr/bin/env python3
import json
import re
import urllib.parse
import urllib.request
import sys
import os
import datetime
import gzip
import subprocess as sp
import html
SEARCH_ENGINE = 'google'
BROWSER = 'firefox'
TERMINAL = ['gnome-terminal', '--']
CONFIG = {
'BROWSER_PATH' : {
'chrome' : ['google-chrome-stable'],
'firefox' : ['firefox'],
'chromium' : ['chromium-browser'],
'brave' : ['brave-browser'],
'lynx' : TERMINAL + ['lynx']
},
'USER_AGENT' : {
'chrome' : 'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
'firefox' : 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0',
'chromium' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/76.0.3809.100 Chrome/76.0.3809.100 Safari/537.36',
'brave' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
'lynx' : 'Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/1.1.1d'
},
'SEARCH_ENGINE_NAME' : {
'google' : 'Google',
'duckduckgo' : 'DuckDuckGo'
},
'SEARCH_URL' : {
'google' : 'https://www.google.com/search?q=',
'duckduckgo' : 'https://duckduckgo.com/?q='
},
'SUGGESTION_URL' : {
'google' : 'https://www.google.com/complete/search?',
'duckduckgo' : 'https://duckduckgo.com/ac/?'
}
}
def cleanhtml(txt):
return re.sub(r'<.*?>', '', txt)
def fetch_suggestions(search_string):
if SEARCH_ENGINE == 'google':
r = {
'q' : search_string,
'cp' : '11',
'client' : 'psy-ab',
'xssi' : 't',
'gs_ri' : 'gws-wiz',
'hl' : 'en-IT',
'authuser' : '0'
}
url = CONFIG['SUGGESTION_URL'][SEARCH_ENGINE] + urllib.parse.urlencode(r)
headers = {
'sec-fetch-mode' : 'cors',
'dnt' : '1',
'accept-encoding' : 'gzip',
'accept-language' : 'en-US;q=0.9,en;q=0.8',
'pragma' : 'no-cache',
'user-agent' : CONFIG['USER_AGENT'][BROWSER],
'accept' : '*/*',
'cache-control' : 'no-cache',
'authority' : 'www.google.com',
'referer' : 'https://www.google.com/',
'sec-fetch-site' : 'same-origin'
}
req = urllib.request.Request(url, headers=headers, method='GET')
reply_data = gzip.decompress(urllib.request.urlopen(req).read()).split(b'n')[1]
reply_data = json.loads(reply_data)
return [ cleanhtml(res[0]).strip() for res in reply_data[0] ]
else:  
if search_string.startswith('!'):
bang_search = True
search_string = search_string.lstrip('!')
else:
bang_search = False
r = {
'q' : search_string,
'callback' : 'autocompleteCallback',
'kl' : 'wt-wt',
'_' : str(int((datetime.datetime.now().timestamp())*1000))
}
url = CONFIG['SUGGESTION_URL'][SEARCH_ENGINE] + urllib.parse.urlencode(r)
if bang_search:
url = url.replace('?q=', '?q=!')
headers = {
'pragma' : 'no-cache',
'dnt' : '1',
'accept-encoding' : 'gzip',
'accept-language' : 'en-US;q=0.9,en;q=0.8',
'user-agent' : CONFIG['USER_AGENT'][BROWSER],
'sec-fetch-mode' : 'no-cors',
'accept' : '*/*',
'cache-control' : 'no-cache',
'authority' : 'duckduckgo.com',
'referer' : 'https://duckduckgo.com/',
'sec-fetch-site' : 'same-origin',
}
req = urllib.request.Request(url, headers=headers, method='GET')
reply_data = gzip.decompress(urllib.request.urlopen(req).read()).decode('utf8')
reply_data = json.loads(re.match(r'autocompleteCallback((.*));', reply_data).group(1))
return [ cleanhtml(res['phrase']).strip() for res in reply_data ]
def main():
search_string = html.unescape((' '.join(sys.argv[1:])).strip())
if search_string.endswith('!'):

search_string = search_string.rstrip('!').strip()
results = fetch_suggestions(search_string)
for r in results:
print(html.unescape(r))
else:
url = CONFIG['SEARCH_URL'][SEARCH_ENGINE] + urllib.parse.quote_plus(search_string)
sp.Popen(CONFIG['BROWSER_PATH'][BROWSER] + [url], stdout=sp.DEVNULL, stderr=sp.DEVNULL, shell=False)
def validate_config(c):
if type(c) != dict:
print('Configuration file must be a JSON object', file=sys.stderr)
sys.exit(1)
for k in ('SEARCH_ENGINE', 'BROWSER', 'TERMINAL'):
if k not in c:
print('Configuration file is missing %s' % k, file=sys.stderr)
sys.exit(1)
for k in ('SEARCH_ENGINE', 'BROWSER'):
if type(c[k]) != str:
print('Configuration Error: The value of %s must be a string' % k, file=sys.stderr)
if type(c['TERMINAL']) != list:
print('Configuration Error: The value of TERMINAL must be a list of strings', file=sys.stderr)
sys.exit(1)
for x in c['TERMINAL']:
if type(x) != str:
print('Configuration Error: The value of TERMINAL must be a list of strings', file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
try:
fname = os.path.expanduser('~/.config/rofi-web-search/config.json')
if os.path.exists(fname):
try:
config = json.loads(open(fname, 'r').read())
except json.JSONDecodeError:
print('Configuration file %s is not a valid JSON' % fname, file=sys.stderr)
sys.exit(1)
validate_config(config)
SEARCH_ENGINE = config['SEARCH_ENGINE']
BROWSER = config['BROWSER']
TERMINAL = config['TERMINAL']
else:
config = {
'SEARCH_ENGINE' : SEARCH_ENGINE,
'BROWSER' : BROWSER,
'TERMINAL' : TERMINAL
}
os.makedirs(os.path.dirname(fname))
f = open(fname, 'w')
f.write(json.dumps(config, indent=4))
f.write('n')
f.close()
main()
except:
sys.exit(1)

键入mario:后的输出

marion cotillard
mario
mario balotelli
mario badescu
mario götze
mario gomez
 mario oyna
           mario mandzukic
mariobet
mario lemina

> mario 

感谢所有答案

编辑:一个有趣的事情是终端在运行程序后展示了相同的行为。

问题代码为:

char search[200];
...
search[i] = '!';
... and other assignments to search
snprintf(esearch, 2000, "firefox -search '%s'",search);//search has never been `` terminated

使用非null终止的字符串调用字符串函数是未定义的行为。

而且,来自另一个帖子:

如果您有一个非null终止的字符串,则不能使用C字符串操作例程。你不能使用strlen,strcpy,[snprintf]或strcat。基本上,任何使用char*但没有单独的长度是不可用的。(强调矿(

要解决这一问题,只需在声明时初始化缓冲区:

char search[200] = {0};

然后将写入search的内容限制为199个字符(search[198](,以免覆盖应保留在search[199]位置的空终止符。

相关内容

最新更新